feat: 代码小调整

This commit is contained in:
meilin.huang
2023-02-07 16:54:44 +08:00
parent fa0cb73ec9
commit 00fee24a85
8 changed files with 528 additions and 592 deletions

View File

@@ -0,0 +1,106 @@
<template>
<div class="instances-box layout-aside">
<el-row type="flex" justify="space-between">
<el-col :span="24"
:style="{ maxHeight: instanceMenuMaxHeight, height: instanceMenuMaxHeight, overflow: 'auto' }"
class="el-scrollbar flex-auto">
<el-menu background-color="transparent" :collapse-transition="false">
<!-- 第一级tag -->
<el-sub-menu v-for="tag of tags" :index="tag.tagPath" :key="tag.tagPath"
@click.stop="clickTag(tag.tagPath)">
<template #title>
<el-icon>
<FolderOpened v-if="opend[tag.tagPath]" color="#e6a23c" />
<Folder v-else />
</el-icon>
<span>{{ tag.tagPath }}</span>
</template>
<slot :tag="tag" name="submenu"></slot>
</el-sub-menu>
</el-menu>
</el-col>
</el-row>
</div>
</template>
<script lang="ts" setup>
import { reactive, toRefs } from 'vue';
const props = defineProps({
instanceMenuMaxHeight: {
type: [Number, String],
},
tags: {
type: Object, required: true
},
})
const state = reactive({
instanceMenuMaxHeight: props.instanceMenuMaxHeight,
tags: props.tags,
opend: {},
})
const {
opend,
} = toRefs(state)
const clickTag = (tagPath: string) => {
if (state.opend[tagPath] === undefined) {
state.opend[tagPath] = true;
return;
}
const opend = state.opend[tagPath]
state.opend[tagPath] = !opend
}
</script>
<style lang="scss">
.instances-box {
.el-menu {
width: 100%;
}
.el-sub-menu {
.checked {
.checked-schema {
color: var(--el-color-primary);
}
}
}
.el-sub-menu__title {
padding-left: 0 !important;
height: 30px !important;
line-height: 30px !important;
}
.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title {
padding-right: 10px;
}
.el-menu-item {
padding-left: 0 !important;
height: 20px !important;
line-height: 20px !important;
}
.el-icon {
margin: 0;
}
.el-sub-menu__icon-arrow {
top: inherit;
right: 10px;
}
}
.instances-pop-form {
.el-form-item {
margin-bottom: unset;
}
}
</style>

View File

@@ -219,7 +219,8 @@
layout="prev, pager, next, total, jumper" v-model:current-page="dt.pageNum" layout="prev, pager, next, total, jumper" v-model:current-page="dt.pageNum"
:page-size="defalutLimit"></el-pagination> :page-size="defalutLimit"></el-pagination>
</el-row> </el-row>
<div style=" font-size: 12px; padding: 0 10px; color: #606266"><span>{{ dt.sql }}</span></div> <div style=" font-size: 12px; padding: 0 10px; color: #606266"><span>{{ dt.sql }}</span>
</div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-container> </el-container>
@@ -258,7 +259,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, nextTick, onMounted, reactive, watch } from 'vue'; import { computed, nextTick, onMounted, reactive } from 'vue';
import { dbApi } from './api'; import { dbApi } from './api';
import { format as sqlFormatter } from 'sql-formatter'; import { format as sqlFormatter } from 'sql-formatter';

View File

@@ -1,19 +1,9 @@
<template> <template>
<div class="instances-box layout-aside"> <tag-menu :instanceMenuMaxHeight="instanceMenuMaxHeight" :tags="instances.tags">
<el-row type="flex" justify="space-between"> <template #submenu="props">
<el-col :span="24" :style="{maxHeight: instanceMenuMaxHeight,height: instanceMenuMaxHeight, overflow:'auto'}" class="el-scrollbar flex-auto">
<el-menu background-color="transparent" ref="menuRef">
<!-- 第一级tag -->
<el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
<template #title>
<el-icon>
<FolderOpened color="#e6a23c" />
</el-icon>
<span>{{ tag.tagPath }}</span>
</template>
<!-- 第二级数据库实例 --> <!-- 第二级数据库实例 -->
<el-sub-menu v-for="inst in instances.tree[tag.tagId]" :index="'instance-' + inst.id" <el-sub-menu v-for="inst in instances.tree[props.tag.tagId]" :index="'instance-' + inst.id"
:key="'instance-' + inst.id" @click="changeInstance(inst, ()=>{})"> :key="'instance-' + inst.id" @click.stop="changeInstance(inst, () => { })">
<template #title> <template #title>
<el-popover placement="right-start" title="数据库实例信息" trigger="hover" :width="210"> <el-popover placement="right-start" title="数据库实例信息" trigger="hover" :width="210">
<template #reference> <template #reference>
@@ -34,9 +24,9 @@
</el-popover> </el-popover>
</template> </template>
<!-- 第三级数据库 --> <!-- 第三级数据库 -->
<el-sub-menu v-for="schema in instances.dbs[inst.id]" :index="inst.id + schema" <el-sub-menu v-for="schema in instances.dbs[inst.id]" :index="inst.id + schema" :key="inst.id + schema"
:key="inst.id + schema" :class="state.nowSchema === (inst.id + schema) && 'checked'" :class="state.nowSchema === (inst.id + schema) && 'checked'"
@click="changeSchema(inst, schema)"> @click.stop="changeSchema(inst, schema)">
<template #title> <template #title>
&nbsp;&nbsp;&nbsp;&nbsp;<el-icon> &nbsp;&nbsp;&nbsp;&nbsp;<el-icon>
<Coin color="#67c23a" /> <Coin color="#67c23a" />
@@ -96,9 +86,8 @@
</template> </template>
<template v-for="sql in instances.sqls[inst.id + schema]"> <template v-for="sql in instances.sqls[inst.id + schema]">
<el-menu-item :index="inst.id + schema + sql.name" <el-menu-item :index="inst.id + schema + sql.name" :key="inst.id + schema + sql.name"
:key="inst.id + schema + sql.name" v-if="sql.show" v-if="sql.show" @click="loadSql(inst, schema, sql.name)">
@click="loadSql(inst, schema, sql.name)">
<template #title> <template #title>
<div style="width: 100%"> <div style="width: 100%">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<el-icon> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<el-icon>
@@ -112,16 +101,14 @@
</el-sub-menu> </el-sub-menu>
</el-sub-menu> </el-sub-menu>
</el-sub-menu> </el-sub-menu>
</el-sub-menu> </template>
</el-menu> </tag-menu>
</el-col>
</el-row>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onBeforeMount, onMounted, reactive, ref, Ref, watch } from 'vue'; import { nextTick, onBeforeMount, onMounted, reactive, ref, Ref, watch } from 'vue';
import { store } from '@/store'; import { store } from '@/store';
import TagMenu from '../../component/TagMenu.vue';
const props = defineProps({ const props = defineProps({
instanceMenuMaxHeight: { instanceMenuMaxHeight: {
@@ -241,46 +228,6 @@ watch(()=>store.state.sqlExecInfo.dbOptInfo, async newValue => {
</script> </script>
<style lang="scss"> <style lang="scss">
.instances-box {
.el-menu {
width: 100%;
}
.el-sub-menu {
.checked {
.checked-schema {
color: var(--el-color-primary);
}
}
}
.el-sub-menu__title {
padding-left: 0 !important;
height: 30px !important;
line-height: 30px !important;
}
.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title {
padding-right: 10px;
}
.el-menu-item {
padding-left: 0 !important;
height: 20px !important;
line-height: 20px !important;
}
.el-icon {
margin: 0;
}
.el-sub-menu__icon-arrow {
top: inherit;
right: 10px;
}
}
.instances-pop-form { .instances-pop-form {
.el-form-item { .el-form-item {
margin-bottom: unset; margin-bottom: unset;

View File

@@ -1,27 +1,8 @@
<template> <template>
<div class="instances-box layout-aside"> <tag-menu :instanceMenuMaxHeight="state.instanceMenuMaxHeight" :tags="instances.tags">
<el-row type="flex" justify="space-between"> <template #submenu="props">
<el-col :span="24" :style="{ <el-sub-menu v-for="inst in instances.tree[props.tag.tagId]" :index="'mongo-instance-' + inst.id"
maxHeight: state.instanceMenuMaxHeight, :key="'mongo-instance-' + inst.id" @click.stop="changeInstance(inst, () => { })">
height: state.instanceMenuMaxHeight,
overflow: 'auto'
}" class="el-scrollbar flex-auto">
<el-menu background-color="transparent" ref="menuRef">
<!-- 第一级tag -->
<el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
<template #title>
<el-icon>
<FolderOpened color="#e6a23c" />
</el-icon>
<span>{{ tag.tagPath }}</span>
</template>
<!-- 第二级数据库实例 -->
<el-sub-menu v-for="inst in instances.tree[tag.tagId]"
:index="'mongo-instance-' + inst.id"
:key="'mongo-instance-' + inst.id"
@click.prevent="changeInstance(inst, ()=>{})"
>
<template #title> <template #title>
<el-popover placement="right-start" title="mongo数据库实例信息" trigger="hover" :width="210"> <el-popover placement="right-start" title="mongo数据库实例信息" trigger="hover" :width="210">
<template #reference> <template #reference>
@@ -38,9 +19,9 @@
</el-popover> </el-popover>
</template> </template>
<!-- 第三级数据库 --> <!-- 第三级数据库 -->
<el-sub-menu v-for="db in instances.dbs[inst.id]" :index="inst.id + db.Name" <el-sub-menu v-for="db in instances.dbs[inst.id]" :index="inst.id + db.Name" :key="inst.id + db.Name"
:key="inst.id + db.Name" :class="state.nowSchema === (inst.id + db.Name) && 'checked'" :class="state.nowSchema === (inst.id + db.Name) && 'checked'"
@click.prevent="changeSchema(inst, db.Name)"> @click.stop="changeSchema(inst, db.Name)">
<template #title> <template #title>
&nbsp;&nbsp;&nbsp;&nbsp;<el-icon> &nbsp;&nbsp;&nbsp;&nbsp;<el-icon>
<Coin color="#67c23a" /> <Coin color="#67c23a" />
@@ -93,17 +74,15 @@
</el-sub-menu> </el-sub-menu>
</el-sub-menu> </el-sub-menu>
</el-sub-menu> </el-sub-menu>
</el-sub-menu> </template>
</el-menu> </tag-menu>
</el-col>
</el-row>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onBeforeMount, onMounted, reactive, ref, Ref, watch } from 'vue'; import { nextTick, onBeforeMount, onMounted, reactive, ref, Ref, watch } from 'vue';
import { formatByteSize } from '@/common/utils/format'; import { formatByteSize } from '@/common/utils/format';
import { store } from '@/store'; import { store } from '@/store';
import TagMenu from '../component/TagMenu.vue';
const props = defineProps({ const props = defineProps({
instances: { instances: {
@@ -119,7 +98,7 @@ onBeforeMount(async () => {
}) })
const setHeight = () => { const setHeight = () => {
state.instanceMenuMaxHeight = window.innerHeight - 140 + 'px'; state.instanceMenuMaxHeight = window.innerHeight - 115 + 'px';
} }
const menuRef = ref(null) as Ref const menuRef = ref(null) as Ref
@@ -226,46 +205,6 @@ watch(()=>store.state.mongoDbOptInfo.dbOptInfo, async newValue => {
</script> </script>
<style lang="scss"> <style lang="scss">
.instances-box {
.el-menu {
width: 100%;
}
.el-sub-menu {
.checked {
.checked-schema {
color: var(--el-color-primary);
}
}
}
.el-sub-menu__title {
padding-left: 0 !important;
height: 30px !important;
line-height: 30px !important;
}
.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title {
padding-right: 10px;
}
.el-menu-item {
padding-left: 0 !important;
height: 20px !important;
line-height: 20px !important;
}
.el-icon {
margin: 0;
}
.el-sub-menu__icon-arrow {
top: inherit;
right: 10px;
}
}
.instances-pop-form { .instances-pop-form {
.el-form-item { .el-form-item {
margin-bottom: unset; margin-bottom: unset;

View File

@@ -1,16 +1,11 @@
<template> <template>
<div> <div>
<el-card>
<el-row> <el-row>
<el-col :span="3"> <el-col :span="4">
<redis-instance-tree <redis-instance-tree @init-load-instances="initLoadInstances" @change-instance="changeInstance"
@init-load-instances="initLoadInstances" @change-schema="loadInitSchema" :instances="state.instances" />
@change-instance="changeInstance"
@change-schema="loadInitSchema"
:instances="state.instances"
/>
</el-col> </el-col>
<el-col :span="19" style="border-left: 1px solid var(--el-card-border-color)"> <el-col :span="20" style="border-left: 1px solid var(--el-card-border-color);">
<el-col class="mt10"> <el-col class="mt10">
<el-form class="search-form" label-position="right" :inline="true" label-width="60px"> <el-form class="search-form" label-position="right" :inline="true" label-width="60px">
<el-form-item label="key" label-width="40px"> <el-form-item label="key" label-width="40px">
@@ -42,7 +37,8 @@
</div> </div>
</el-form> </el-form>
</el-col> </el-col>
<el-table v-loading="state.loading" :data="state.keys" stripe :highlight-current-row="true" style="cursor: pointer"> <el-table v-loading="state.loading" :data="state.keys" stripe :highlight-current-row="true"
style="cursor: pointer">
<el-table-column show-overflow-tooltip prop="key" label="key"></el-table-column> <el-table-column show-overflow-tooltip prop="key" label="key"></el-table-column>
<el-table-column prop="type" label="type" width="80"> <el-table-column prop="type" label="type" width="80">
<template #default="scope"> <template #default="scope">
@@ -66,8 +62,6 @@
</el-col> </el-col>
</el-row> </el-row>
</el-card>
<div style="text-align: center; margin-top: 10px"></div> <div style="text-align: center; margin-top: 10px"></div>
<hash-value v-model:visible="hashValueDialog.visible" :operationType="dataEdit.operationType" <hash-value v-model:visible="hashValueDialog.visible" :operationType="dataEdit.operationType"
@@ -331,19 +325,19 @@ const initLoadInstances = async ()=>{
// 实例 // 实例
arr.push(db) arr.push(db)
state.instances.tree[db.tagId] = arr; state.instances.tree[db.tagId] = arr;
} }
} }
const changeInstance = async (inst: any, fn: Function) => { const changeInstance = async (inst: any, fn: Function) => {
let dbs = state.instances.dbs[inst.id] || [] let dbs = inst.db.split(',').map((x: string) => {
if(dbs.length <=0 ){ return { name: `db${x}`, keys: 0 }
const res = await redisApi.redisInfo.request({ id: inst.id, host:inst.host });
for (let db in res.Keyspace){
dbs.push({
name: db,
keys: res.Keyspace[db]?.split(',')[0]?.split('=')[1] || 0
}) })
const res = await redisApi.redisInfo.request({ id: inst.id, host: inst.host, section: "Keyspace" });
for (let db in res.Keyspace) {
for (let d of dbs) {
if (db == d.name) {
d.keys = res.Keyspace[db]?.split(',')[0]?.split('=')[1] || 0
}
} }
} }

View File

@@ -1,68 +1,46 @@
<template> <template>
<div class="instances-box layout-aside"> <tag-menu :instanceMenuMaxHeight="state.instanceMenuMaxHeight" :tags="instances.tags">
<el-row type="flex" justify="space-between"> <template #submenu="props">
<el-col :span="24" :style="{ <el-sub-menu v-for="inst in instances.tree[props.tag.tagId]" :index="'redis-instance-' + inst.id"
maxHeight: state.instanceMenuMaxHeight, :key="'redis-instance-' + inst.id" @click.stop="changeInstance(inst)">
height: state.instanceMenuMaxHeight,
overflow:'auto'
}" class="el-scrollbar flex-auto">
<el-menu background-color="transparent" ref="menuRef">
<!-- 第一级tag -->
<el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
<template #title> <template #title>
<el-icon><FolderOpened color="#e6a23c"/></el-icon> <el-popover placement="right-start" title="redis实例信息" trigger="hover" :width="210">
<span>{{ tag.tagPath }}</span>
</template>
<!-- 第二级数据库实例 -->
<el-sub-menu v-for="inst in instances.tree[tag.tagId]"
:index="'redis-instance-' + inst.id"
:key="'redis-instance-' + inst.id"
@click.prevent="changeInstance(inst)"
>
<template #title>
<el-popover
placement="right-start"
title="mongo数据库实例信息"
trigger="hover"
:width="210"
>
<template #reference> <template #reference>
<span>&nbsp;&nbsp;<el-icon><MostlyCloudy color="#409eff"/></el-icon>{{ inst.name }}</span> <span>&nbsp;&nbsp;<el-icon>
<MostlyCloudy color="#409eff" />
</el-icon>{{ inst.name }}</span>
</template> </template>
<template #default> <template #default>
<el-form class="instances-pop-form" label-width="55px" :size="'small'"> <el-form class="instances-pop-form" label-width="55px" :size="'small'">
<el-form-item label="名称:">{{ inst.name }}</el-form-item> <el-form-item label="名称:">{{ inst.name }}</el-form-item>
<el-form-item label="链接:">{{ inst.host }}</el-form-item> <el-form-item label="链接:">{{ inst.host }}</el-form-item>
<el-form-item label="备注:">{{ inst.remark }}</el-form-item>
</el-form> </el-form>
</template> </template>
</el-popover> </el-popover>
</template> </template>
<!-- 第三级数据库 --> <!-- 第三级数据库 -->
<el-sub-menu v-for="db in instances.dbs[inst.id]" <el-menu-item v-for="db in instances.dbs[inst.id]" :index="inst.id + db.name" :key="inst.id + db.name"
:index="inst.id + db.name"
:key="inst.id + db.name"
:class="state.nowSchema === (inst.id + db.name) && 'checked'" :class="state.nowSchema === (inst.id + db.name) && 'checked'"
@click.prevent="changeSchema(inst, db.name)" @click="changeSchema(inst, db.name)">
>
<template #title> <template #title>
&nbsp;&nbsp;&nbsp;&nbsp;<el-icon><Coin color="#67c23a"/></el-icon> &nbsp;&nbsp;&nbsp;&nbsp;<el-icon>
<Coin color="#67c23a" />
</el-icon>
<span class="checked-schema"> <span class="checked-schema">
{{ db.name }} [{{ db.keys }}] {{ db.name }} [{{ db.keys }}]
</span> </span>
</template> </template>
</el-menu-item>
</el-sub-menu> </el-sub-menu>
</el-sub-menu> </template>
</el-sub-menu> </tag-menu>
</el-menu>
</el-col>
</el-row>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onBeforeMount, onMounted, reactive, Ref, ref, watch } from 'vue'; import { onBeforeMount, onMounted, reactive, Ref, ref, watch } from 'vue';
import { store } from '@/store'; import { store } from '@/store';
import TagMenu from '../component/TagMenu.vue';
defineProps({ defineProps({
instances: { instances: {
@@ -78,7 +56,7 @@ onBeforeMount(async ()=>{
}) })
const setHeight = () => { const setHeight = () => {
state.instanceMenuMaxHeight = window.innerHeight - 140 + 'px'; state.instanceMenuMaxHeight = window.innerHeight - 115 + 'px';
} }
const menuRef = ref(null) as Ref; const menuRef = ref(null) as Ref;
@@ -138,39 +116,6 @@ watch(()=>store.state.redisDbOptInfo.dbOptInfo, async newValue =>{
</script> </script>
<style lang="scss"> <style lang="scss">
.instances-box {
.el-menu{
width: 275px;
}
.el-sub-menu{
.checked{
.checked-schema{
color: var(--el-color-primary);
}
}
}
.el-sub-menu__title{
padding-left: 0 !important;
height: 30px !important;
line-height: 30px !important;
}
.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title{
padding-right: 10px;
}
.el-menu-item{
padding-left: 0 !important;
height: 20px !important;
line-height: 20px !important;
}
.el-icon{
margin: 0;
}
.el-sub-menu__icon-arrow{
top:inherit;
right: 10px;
}
}
.instances-pop-form { .instances-pop-form {
.el-form-item { .el-form-item {
margin-bottom: unset; margin-bottom: unset;

View File

@@ -76,36 +76,42 @@ func (r *Redis) RedisInfo(rc *req.Ctx) {
g := rc.GinCtx g := rc.GinCtx
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")), 0) ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")), 0)
var res string section := rc.GinCtx.Query("section")
var err error
mode := ri.Info.Mode mode := ri.Info.Mode
ctx := context.Background() ctx := context.Background()
var redisCli *redis.Client
if mode == "" || mode == entity.RedisModeStandalone || mode == entity.RedisModeSentinel { if mode == "" || mode == entity.RedisModeStandalone || mode == entity.RedisModeSentinel {
res, err = ri.Cli.Info(ctx).Result() redisCli = ri.Cli
} else if mode == entity.RedisModeCluster { } else if mode == entity.RedisModeCluster {
host := rc.GinCtx.Query("host") host := rc.GinCtx.Query("host")
biz.NotEmpty(host, "集群模式host信息不能为空") biz.NotEmpty(host, "集群模式host信息不能为空")
clusterClient := ri.ClusterCli clusterClient := ri.ClusterCli
var redisClient *redis.Client
// 遍历集群的master节点找到该redis client // 遍历集群的master节点找到该redis client
clusterClient.ForEachMaster(ctx, func(ctx context.Context, client *redis.Client) error { clusterClient.ForEachMaster(ctx, func(ctx context.Context, client *redis.Client) error {
if host == client.Options().Addr { if host == client.Options().Addr {
redisClient = client redisCli = client
} }
return nil return nil
}) })
if redisClient == nil { if redisCli == nil {
// 遍历集群的slave节点找到该redis client // 遍历集群的slave节点找到该redis client
clusterClient.ForEachSlave(ctx, func(ctx context.Context, client *redis.Client) error { clusterClient.ForEachSlave(ctx, func(ctx context.Context, client *redis.Client) error {
if host == client.Options().Addr { if host == client.Options().Addr {
redisClient = client redisCli = client
} }
return nil return nil
}) })
} }
biz.NotNil(redisClient, "该实例不在该集群中") biz.NotNil(redisCli, "该实例不在该集群中")
res, err = redisClient.Info(ctx).Result() }
var res string
var err error
if section == "" {
res, err = ri.Cli.Info(ctx).Result()
} else {
res, err = ri.Cli.Info(ctx, section).Result()
} }
biz.ErrIsNilAppendErr(err, "获取redis info失败: %s") biz.ErrIsNilAppendErr(err, "获取redis info失败: %s")

View File

@@ -7,8 +7,6 @@ type Redis struct {
Name *string `json:"name"` Name *string `json:"name"`
Host *string `json:"host"` Host *string `json:"host"`
Db string `json:"db"` Db string `json:"db"`
ProjectId *int64 `json:"projectId"`
Project *string `json:"project"`
Mode *string `json:"mode"` Mode *string `json:"mode"`
EnableSshTunnel *int8 `json:"enableSshTunnel"` // 是否启用ssh隧道 EnableSshTunnel *int8 `json:"enableSshTunnel"` // 是否启用ssh隧道
SshTunnelMachineId *uint64 `json:"sshTunnelMachineId"` // ssh隧道机器id SshTunnelMachineId *uint64 `json:"sshTunnelMachineId"` // ssh隧道机器id