mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 16:30:25 +08:00 
			
		
		
		
	feat: 代码小调整
This commit is contained in:
		
							
								
								
									
										106
									
								
								mayfly_go_web/src/views/ops/component/TagMenu.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								mayfly_go_web/src/views/ops/component/TagMenu.vue
									
									
									
									
									
										Normal 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>
 | 
				
			||||||
@@ -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';
 | 
				
			||||||
@@ -1754,14 +1755,14 @@ const loadSchemaTables = async (inst: any, schema: string, fn: Function) => {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        tables.forEach((a: any) => a.show = true)
 | 
					        tables.forEach((a: any) => a.show = true)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  fn(state.instances.tables[id+schema])
 | 
					    fn(state.instances.tables[id + schema])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 选择数据库实例
 | 
					// 选择数据库实例
 | 
				
			||||||
const changeInstance = (inst: any, fn?: Function) => {
 | 
					const changeInstance = (inst: any, fn?: Function) => {
 | 
				
			||||||
    state.dbId = inst.id
 | 
					    state.dbId = inst.id
 | 
				
			||||||
    state.dbType = inst.type
 | 
					    state.dbType = inst.type
 | 
				
			||||||
  fn && fn()
 | 
					    fn && fn()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
// 选择数据库
 | 
					// 选择数据库
 | 
				
			||||||
const changeSchema = (inst: any, schema: string) => {
 | 
					const changeSchema = (inst: any, schema: string) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,127 +1,114 @@
 | 
				
			|||||||
<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">
 | 
					            <el-sub-menu v-for="inst in instances.tree[props.tag.tagId]" :index="'instance-' + inst.id"
 | 
				
			||||||
                    <!-- 第一级:tag -->
 | 
					                :key="'instance-' + inst.id" @click.stop="changeInstance(inst, () => { })">
 | 
				
			||||||
                    <el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
 | 
					                <template #title>
 | 
				
			||||||
                        <template #title>
 | 
					                    <el-popover placement="right-start" title="数据库实例信息" trigger="hover" :width="210">
 | 
				
			||||||
                            <el-icon>
 | 
					                        <template #reference>
 | 
				
			||||||
                                <FolderOpened color="#e6a23c" />
 | 
					                            <span>  <el-icon>
 | 
				
			||||||
                            </el-icon>
 | 
					                                    <MostlyCloudy color="#409eff" />
 | 
				
			||||||
                            <span>{{ tag.tagPath }}</span>
 | 
					                                </el-icon>{{ inst.name }}</span>
 | 
				
			||||||
                        </template>
 | 
					                        </template>
 | 
				
			||||||
                        <!-- 第二级:数据库实例 -->
 | 
					                        <template #default>
 | 
				
			||||||
                        <el-sub-menu v-for="inst in instances.tree[tag.tagId]" :index="'instance-' + inst.id"
 | 
					                            <el-form class="instances-pop-form" label-width="55px" :size="'small'">
 | 
				
			||||||
                            :key="'instance-' + inst.id" @click="changeInstance(inst, ()=>{})">
 | 
					                                <el-form-item label="类型:">{{ inst.type }}</el-form-item>
 | 
				
			||||||
 | 
					                                <el-form-item label="链接:">{{ inst.host }}:{{ inst.port }}</el-form-item>
 | 
				
			||||||
 | 
					                                <el-form-item label="用户:">{{ inst.username }}</el-form-item>
 | 
				
			||||||
 | 
					                                <el-form-item v-if="inst.remark" label="备注:">{{
 | 
				
			||||||
 | 
					                                    inst.remark
 | 
				
			||||||
 | 
					                                }}</el-form-item>
 | 
				
			||||||
 | 
					                            </el-form>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                    </el-popover>
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					                <!-- 第三级:数据库 -->
 | 
				
			||||||
 | 
					                <el-sub-menu v-for="schema in instances.dbs[inst.id]" :index="inst.id + schema" :key="inst.id + schema"
 | 
				
			||||||
 | 
					                    :class="state.nowSchema === (inst.id + schema) && 'checked'"
 | 
				
			||||||
 | 
					                    @click.stop="changeSchema(inst, schema)">
 | 
				
			||||||
 | 
					                    <template #title>
 | 
				
			||||||
 | 
					                            <el-icon>
 | 
				
			||||||
 | 
					                            <Coin color="#67c23a" />
 | 
				
			||||||
 | 
					                        </el-icon>
 | 
				
			||||||
 | 
					                        <span class="checked-schema">{{ schema }}</span>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                    <!-- 第四级 01:表 -->
 | 
				
			||||||
 | 
					                    <el-sub-menu :index="inst.id + schema + '-table'">
 | 
				
			||||||
 | 
					                        <template #title>
 | 
				
			||||||
 | 
					                            <div style="width: 100%" @click="loadTableNames(inst, schema, () => { })">
 | 
				
			||||||
 | 
					                                      <el-icon>
 | 
				
			||||||
 | 
					                                    <Calendar color="#409eff" />
 | 
				
			||||||
 | 
					                                </el-icon>
 | 
				
			||||||
 | 
					                                <span>表</span>
 | 
				
			||||||
 | 
					                                <el-icon v-show="state.loading[inst.id + schema]" class="is-loading">
 | 
				
			||||||
 | 
					                                    <Loading />
 | 
				
			||||||
 | 
					                                </el-icon>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                        <el-menu-item :index="inst.id + schema + '-tableSearch'"
 | 
				
			||||||
 | 
					                            :key="inst.id + schema + '-tableSearch'">
 | 
				
			||||||
                            <template #title>
 | 
					                            <template #title>
 | 
				
			||||||
                                <el-popover placement="right-start" title="数据库实例信息" trigger="hover" :width="210">
 | 
					                                        
 | 
				
			||||||
                                    <template #reference>
 | 
					                                <el-input size="small" placeholder="过滤表" clearable
 | 
				
			||||||
                                        <span>  <el-icon>
 | 
					                                    @change="filterTableName(inst.id, schema)"
 | 
				
			||||||
                                                <MostlyCloudy color="#409eff" />
 | 
					                                    @keyup="(e: any) => filterTableName(inst.id, schema, e)"
 | 
				
			||||||
                                            </el-icon>{{ inst.name }}</span>
 | 
					                                    v-model="state.filterParam[inst.id + schema]" />
 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                    <template #default>
 | 
					 | 
				
			||||||
                                        <el-form class="instances-pop-form" label-width="55px" :size="'small'">
 | 
					 | 
				
			||||||
                                            <el-form-item label="类型:">{{ inst.type }}</el-form-item>
 | 
					 | 
				
			||||||
                                            <el-form-item label="链接:">{{ inst.host }}:{{ inst.port }}</el-form-item>
 | 
					 | 
				
			||||||
                                            <el-form-item label="用户:">{{ inst.username }}</el-form-item>
 | 
					 | 
				
			||||||
                                            <el-form-item v-if="inst.remark" label="备注:">{{
 | 
					 | 
				
			||||||
                                                inst.remark
 | 
					 | 
				
			||||||
                                            }}</el-form-item>
 | 
					 | 
				
			||||||
                                        </el-form>
 | 
					 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                </el-popover>
 | 
					 | 
				
			||||||
                            </template>
 | 
					                            </template>
 | 
				
			||||||
                            <!-- 第三级:数据库 -->
 | 
					                        </el-menu-item>
 | 
				
			||||||
                            <el-sub-menu v-for="schema in instances.dbs[inst.id]" :index="inst.id + schema"
 | 
					
 | 
				
			||||||
                                :key="inst.id + schema" :class="state.nowSchema === (inst.id + schema) && 'checked'"
 | 
					                        <template v-for="tb in instances.tables[inst.id + schema]">
 | 
				
			||||||
                                @click="changeSchema(inst, schema)">
 | 
					                            <el-menu-item :index="inst.id + schema + tb.tableName"
 | 
				
			||||||
 | 
					                                :key="inst.id + schema + tb.tableName" v-if="tb.show"
 | 
				
			||||||
 | 
					                                @click="loadTableData(inst, schema, tb.tableName)">
 | 
				
			||||||
                                <template #title>
 | 
					                                <template #title>
 | 
				
			||||||
                                        <el-icon>
 | 
					                                    <div style="width: 100%">
 | 
				
			||||||
                                        <Coin color="#67c23a" />
 | 
					                                               <el-icon>
 | 
				
			||||||
                                    </el-icon>
 | 
					                                            <Calendar color="#409eff" />
 | 
				
			||||||
                                    <span class="checked-schema">{{ schema }}</span>
 | 
					 | 
				
			||||||
                                </template>
 | 
					 | 
				
			||||||
                                <!-- 第四级 01:表 -->
 | 
					 | 
				
			||||||
                                <el-sub-menu :index="inst.id + schema + '-table'">
 | 
					 | 
				
			||||||
                                    <template #title>
 | 
					 | 
				
			||||||
                                        <div style="width: 100%" @click="loadTableNames(inst, schema, ()=>{})">
 | 
					 | 
				
			||||||
                                                <el-icon>
 | 
					 | 
				
			||||||
                                              <Calendar color="#409eff"/>
 | 
					 | 
				
			||||||
                                            </el-icon>
 | 
					 | 
				
			||||||
                                            <span>表</span>
 | 
					 | 
				
			||||||
                                            <el-icon v-show="state.loading[inst.id + schema]" class="is-loading">
 | 
					 | 
				
			||||||
                                                <Loading />
 | 
					 | 
				
			||||||
                                            </el-icon>
 | 
					 | 
				
			||||||
                                        </div>
 | 
					 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                    <el-menu-item :index="inst.id + schema + '-tableSearch'"
 | 
					 | 
				
			||||||
                                        :key="inst.id + schema + '-tableSearch'">
 | 
					 | 
				
			||||||
                                        <template #title>
 | 
					 | 
				
			||||||
                                                    
 | 
					 | 
				
			||||||
                                            <el-input size="small" placeholder="过滤表" clearable
 | 
					 | 
				
			||||||
                                                @change="filterTableName(inst.id, schema)"
 | 
					 | 
				
			||||||
                                                @keyup="(e: any) => filterTableName(inst.id, schema, e)"
 | 
					 | 
				
			||||||
                                                v-model="state.filterParam[inst.id + schema]" />
 | 
					 | 
				
			||||||
                                        </template>
 | 
					 | 
				
			||||||
                                    </el-menu-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                    <template v-for="tb in instances.tables[inst.id + schema]">
 | 
					 | 
				
			||||||
                                        <el-menu-item :index="inst.id + schema + tb.tableName"
 | 
					 | 
				
			||||||
                                            :key="inst.id + schema + tb.tableName" v-if="tb.show"
 | 
					 | 
				
			||||||
                                            @click="loadTableData(inst, schema, tb.tableName)">
 | 
					 | 
				
			||||||
                                            <template #title>
 | 
					 | 
				
			||||||
                                                <div style="width: 100%">
 | 
					 | 
				
			||||||
                                                           <el-icon>
 | 
					 | 
				
			||||||
                                                        <Calendar color="#409eff" />
 | 
					 | 
				
			||||||
                                                    </el-icon>
 | 
					 | 
				
			||||||
                                                    <el-tooltip v-if="tb.tableComment" effect="customized"
 | 
					 | 
				
			||||||
                                                        :content="tb.tableComment" placement="right">
 | 
					 | 
				
			||||||
                                                        {{ tb.tableName }}
 | 
					 | 
				
			||||||
                                                    </el-tooltip>
 | 
					 | 
				
			||||||
                                                    <span v-else>{{ tb.tableName }}</span>
 | 
					 | 
				
			||||||
                                                </div>
 | 
					 | 
				
			||||||
                                            </template>
 | 
					 | 
				
			||||||
                                        </el-menu-item>
 | 
					 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                </el-sub-menu>
 | 
					 | 
				
			||||||
                                <!-- 第四级 02:sql -->
 | 
					 | 
				
			||||||
                                <el-sub-menu :index="inst.id + schema + '-sql'">
 | 
					 | 
				
			||||||
                                    <template #title>
 | 
					 | 
				
			||||||
                                              <el-icon>
 | 
					 | 
				
			||||||
                                            <List color="#f56c6c" />
 | 
					 | 
				
			||||||
                                        </el-icon>
 | 
					                                        </el-icon>
 | 
				
			||||||
                                        <span>sql</span>
 | 
					                                        <el-tooltip v-if="tb.tableComment" effect="customized"
 | 
				
			||||||
                                    </template>
 | 
					                                            :content="tb.tableComment" placement="right">
 | 
				
			||||||
 | 
					                                            {{ tb.tableName }}
 | 
				
			||||||
                                    <template v-for="sql in instances.sqls[inst.id + schema]">
 | 
					                                        </el-tooltip>
 | 
				
			||||||
                                        <el-menu-item :index="inst.id + schema + sql.name"
 | 
					                                        <span v-else>{{ tb.tableName }}</span>
 | 
				
			||||||
                                            :key="inst.id + schema + sql.name" v-if="sql.show"
 | 
					                                    </div>
 | 
				
			||||||
                                            @click="loadSql(inst, schema, sql.name)">
 | 
					                                </template>
 | 
				
			||||||
                                            <template #title>
 | 
					                            </el-menu-item>
 | 
				
			||||||
                                                <div style="width: 100%">
 | 
					                        </template>
 | 
				
			||||||
                                                           <el-icon>
 | 
					 | 
				
			||||||
                                                        <Calendar color="#409eff" />
 | 
					 | 
				
			||||||
                                                    </el-icon>
 | 
					 | 
				
			||||||
                                                    <span>{{ sql.name }}</span>
 | 
					 | 
				
			||||||
                                                </div>
 | 
					 | 
				
			||||||
                                            </template>
 | 
					 | 
				
			||||||
                                        </el-menu-item>
 | 
					 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                </el-sub-menu>
 | 
					 | 
				
			||||||
                            </el-sub-menu>
 | 
					 | 
				
			||||||
                        </el-sub-menu>
 | 
					 | 
				
			||||||
                    </el-sub-menu>
 | 
					                    </el-sub-menu>
 | 
				
			||||||
                </el-menu>
 | 
					                    <!-- 第四级 02:sql -->
 | 
				
			||||||
            </el-col>
 | 
					                    <el-sub-menu :index="inst.id + schema + '-sql'">
 | 
				
			||||||
        </el-row>
 | 
					                        <template #title>
 | 
				
			||||||
    </div>
 | 
					                                  <el-icon>
 | 
				
			||||||
 | 
					                                <List color="#f56c6c" />
 | 
				
			||||||
 | 
					                            </el-icon>
 | 
				
			||||||
 | 
					                            <span>sql</span>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        <template v-for="sql in instances.sqls[inst.id + schema]">
 | 
				
			||||||
 | 
					                            <el-menu-item :index="inst.id + schema + sql.name" :key="inst.id + schema + sql.name"
 | 
				
			||||||
 | 
					                                v-if="sql.show" @click="loadSql(inst, schema, sql.name)">
 | 
				
			||||||
 | 
					                                <template #title>
 | 
				
			||||||
 | 
					                                    <div style="width: 100%">
 | 
				
			||||||
 | 
					                                               <el-icon>
 | 
				
			||||||
 | 
					                                            <Calendar color="#409eff" />
 | 
				
			||||||
 | 
					                                        </el-icon>
 | 
				
			||||||
 | 
					                                        <span>{{ sql.name }}</span>
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-menu-item>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                    </el-sub-menu>
 | 
				
			||||||
 | 
					                </el-sub-menu>
 | 
				
			||||||
 | 
					            </el-sub-menu>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					    </tag-menu>
 | 
				
			||||||
</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: {
 | 
				
			||||||
@@ -158,8 +145,8 @@ const initLoadInstances = () => {
 | 
				
			|||||||
 * @param inst 选中的实例对象
 | 
					 * @param inst 选中的实例对象
 | 
				
			||||||
 * @param fn 选中的实例对象后的回调函数
 | 
					 * @param fn 选中的实例对象后的回调函数
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const changeInstance = (inst : any, fn: Function) => {
 | 
					const changeInstance = (inst: any, fn: Function) => {
 | 
				
			||||||
  emits('changeInstance', inst, fn)
 | 
					    emits('changeInstance', inst, fn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 改变选中的数据库schema
 | 
					 * 改变选中的数据库schema
 | 
				
			||||||
@@ -178,9 +165,9 @@ const changeSchema = (inst: any, schema: string) => {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
const loadTableNames = async (inst: any, schema: string, fn: Function) => {
 | 
					const loadTableNames = async (inst: any, schema: string, fn: Function) => {
 | 
				
			||||||
    state.loading[inst.id + schema] = true
 | 
					    state.loading[inst.id + schema] = true
 | 
				
			||||||
  await emits('loadTableNames', inst, schema, (res: any[])=>{
 | 
					    await emits('loadTableNames', inst, schema, (res: any[]) => {
 | 
				
			||||||
        state.loading[inst.id + schema] = false
 | 
					        state.loading[inst.id + schema] = false
 | 
				
			||||||
    fn && fn(res)
 | 
					        fn && fn(res)
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -206,81 +193,41 @@ const filterTableName = (instId: number, schema: string, event?: any) => {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const selectDb = async (val?: any) => {
 | 
					const selectDb = async (val?: any) => {
 | 
				
			||||||
  let info = val || store.state.sqlExecInfo.dbOptInfo;
 | 
					    let info = val || store.state.sqlExecInfo.dbOptInfo;
 | 
				
			||||||
  if (info && info.dbId) {
 | 
					    if (info && info.dbId) {
 | 
				
			||||||
    const {tagPath, dbId, db} = info
 | 
					        const { tagPath, dbId, db } = info
 | 
				
			||||||
    menuRef.value.open(tagPath);
 | 
					        menuRef.value.open(tagPath);
 | 
				
			||||||
    menuRef.value.open('instance-' + dbId);
 | 
					        menuRef.value.open('instance-' + dbId);
 | 
				
			||||||
    await changeInstance({id: dbId}, () => {
 | 
					        await changeInstance({ id: dbId }, () => {
 | 
				
			||||||
      // 加载数据库
 | 
					            // 加载数据库
 | 
				
			||||||
      nextTick(async () => {
 | 
					            nextTick(async () => {
 | 
				
			||||||
        menuRef.value.open(dbId + db)
 | 
					                menuRef.value.open(dbId + db)
 | 
				
			||||||
        state.nowSchema = (dbId+db)
 | 
					                state.nowSchema = (dbId + db)
 | 
				
			||||||
        // 加载集合列表
 | 
					                // 加载集合列表
 | 
				
			||||||
        await nextTick(async () => {
 | 
					                await nextTick(async () => {
 | 
				
			||||||
          await loadTableNames({id: dbId}, db, (res: any[]) => {
 | 
					                    await loadTableNames({ id: dbId }, db, (res: any[]) => {
 | 
				
			||||||
            // 展开集合列表
 | 
					                        // 展开集合列表
 | 
				
			||||||
            menuRef.value.open(dbId + db + '-table')
 | 
					                        menuRef.value.open(dbId + db + '-table')
 | 
				
			||||||
            console.log(res)
 | 
					                        console.log(res)
 | 
				
			||||||
          })
 | 
					                    })
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      })
 | 
					    }
 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(()=>{
 | 
					onMounted(() => {
 | 
				
			||||||
  selectDb();
 | 
					    selectDb();
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(()=>store.state.sqlExecInfo.dbOptInfo, async newValue => {
 | 
					watch(() => store.state.sqlExecInfo.dbOptInfo, async newValue => {
 | 
				
			||||||
  await selectDb(newValue)
 | 
					    await selectDb(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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,109 +1,88 @@
 | 
				
			|||||||
<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,
 | 
					                <template #title>
 | 
				
			||||||
                overflow: 'auto'
 | 
					                    <el-popover placement="right-start" title="mongo数据库实例信息" trigger="hover" :width="210">
 | 
				
			||||||
            }" class="el-scrollbar flex-auto">
 | 
					                        <template #reference>
 | 
				
			||||||
 | 
					                            <span>  <el-icon>
 | 
				
			||||||
        <el-menu background-color="transparent" ref="menuRef">
 | 
					                                    <MostlyCloudy color="#409eff" />
 | 
				
			||||||
                    <!-- 第一级:tag -->
 | 
					                                </el-icon>{{ inst.name }}</span>
 | 
				
			||||||
                    <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>
 | 
					                        </template>
 | 
				
			||||||
                        <!-- 第二级:数据库实例 -->
 | 
					                        <template #default>
 | 
				
			||||||
                        <el-sub-menu v-for="inst in instances.tree[tag.tagId]"
 | 
					                            <el-form class="instances-pop-form" label-width="55px" :size="'small'">
 | 
				
			||||||
                                     :index="'mongo-instance-' + inst.id"
 | 
					                                <el-form-item label="名称:">{{ inst.name }}</el-form-item>
 | 
				
			||||||
                                     :key="'mongo-instance-' + inst.id"
 | 
					                                <el-form-item label="链接:">{{ inst.uri }}</el-form-item>
 | 
				
			||||||
                                     @click.prevent="changeInstance(inst, ()=>{})"
 | 
					                            </el-form>
 | 
				
			||||||
                        >
 | 
					                        </template>
 | 
				
			||||||
 | 
					                    </el-popover>
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					                <!-- 第三级:数据库 -->
 | 
				
			||||||
 | 
					                <el-sub-menu v-for="db in instances.dbs[inst.id]" :index="inst.id + db.Name" :key="inst.id + db.Name"
 | 
				
			||||||
 | 
					                    :class="state.nowSchema === (inst.id + db.Name) && 'checked'"
 | 
				
			||||||
 | 
					                    @click.stop="changeSchema(inst, db.Name)">
 | 
				
			||||||
 | 
					                    <template #title>
 | 
				
			||||||
 | 
					                            <el-icon>
 | 
				
			||||||
 | 
					                            <Coin color="#67c23a" />
 | 
				
			||||||
 | 
					                        </el-icon>
 | 
				
			||||||
 | 
					                        <span class="checked-schema">
 | 
				
			||||||
 | 
					                            {{ db.Name }}
 | 
				
			||||||
 | 
					                            <span style="color: #8492a6;font-size: 13px">[{{
 | 
				
			||||||
 | 
					                                formatByteSize(db.SizeOnDisk)
 | 
				
			||||||
 | 
					                            }}]</span>
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                    <!-- 第四级 01:表 -->
 | 
				
			||||||
 | 
					                    <el-sub-menu :index="inst.id + db.Name + '-table'">
 | 
				
			||||||
 | 
					                        <template #title>
 | 
				
			||||||
 | 
					                            <div style="width: 100%" @click="loadTableNames(inst, db.Name, () => { })">
 | 
				
			||||||
 | 
					                                      <el-icon>
 | 
				
			||||||
 | 
					                                    <Calendar color="#409eff" />
 | 
				
			||||||
 | 
					                                </el-icon>
 | 
				
			||||||
 | 
					                                <span>集合</span>
 | 
				
			||||||
 | 
					                                <el-icon v-show="state.loading[inst.id + db.Name]" class="is-loading">
 | 
				
			||||||
 | 
					                                    <Loading />
 | 
				
			||||||
 | 
					                                </el-icon>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                        <el-menu-item :index="inst.id + db.Name + '-tableSearch'"
 | 
				
			||||||
 | 
					                            :key="inst.id + db.Name + '-tableSearch'">
 | 
				
			||||||
                            <template #title>
 | 
					                            <template #title>
 | 
				
			||||||
                                <el-popover placement="right-start" title="mongo数据库实例信息" trigger="hover" :width="210">
 | 
					                                        
 | 
				
			||||||
                                    <template #reference>
 | 
					                                <el-input size="small" placeholder="过滤" clearable
 | 
				
			||||||
                                        <span>  <el-icon>
 | 
					                                    @change="filterTableName(inst.id, db.Name)"
 | 
				
			||||||
                                                <MostlyCloudy color="#409eff" />
 | 
					                                    @keyup="(e: any) => filterTableName(inst.id, db.Name, e)"
 | 
				
			||||||
                                            </el-icon>{{ inst.name }}</span>
 | 
					                                    v-model="state.filterParam[inst.id + db.Name]" />
 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                    <template #default>
 | 
					 | 
				
			||||||
                                        <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.uri }}</el-form-item>
 | 
					 | 
				
			||||||
                                        </el-form>
 | 
					 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                </el-popover>
 | 
					 | 
				
			||||||
                            </template>
 | 
					                            </template>
 | 
				
			||||||
                            <!-- 第三级:数据库 -->
 | 
					                        </el-menu-item>
 | 
				
			||||||
                            <el-sub-menu v-for="db in instances.dbs[inst.id]" :index="inst.id + db.Name"
 | 
					 | 
				
			||||||
                                :key="inst.id + db.Name" :class="state.nowSchema === (inst.id + db.Name) && 'checked'"
 | 
					 | 
				
			||||||
                                @click.prevent="changeSchema(inst, db.Name)">
 | 
					 | 
				
			||||||
                                <template #title>
 | 
					 | 
				
			||||||
                                        <el-icon>
 | 
					 | 
				
			||||||
                                        <Coin color="#67c23a" />
 | 
					 | 
				
			||||||
                                    </el-icon>
 | 
					 | 
				
			||||||
                                    <span class="checked-schema">
 | 
					 | 
				
			||||||
                                        {{ db.Name }}
 | 
					 | 
				
			||||||
                                        <span style="color: #8492a6;font-size: 13px">[{{
 | 
					 | 
				
			||||||
                                            formatByteSize(db.SizeOnDisk)
 | 
					 | 
				
			||||||
                                        }}]</span>
 | 
					 | 
				
			||||||
                                    </span>
 | 
					 | 
				
			||||||
                                </template>
 | 
					 | 
				
			||||||
                                <!-- 第四级 01:表 -->
 | 
					 | 
				
			||||||
                                <el-sub-menu :index="inst.id + db.Name + '-table'">
 | 
					 | 
				
			||||||
                                    <template #title>
 | 
					 | 
				
			||||||
                                        <div style="width: 100%" @click="loadTableNames(inst, db.Name, ()=>{})">
 | 
					 | 
				
			||||||
                                                  <el-icon>
 | 
					 | 
				
			||||||
                                                <Calendar color="#409eff"/>
 | 
					 | 
				
			||||||
                                            </el-icon>
 | 
					 | 
				
			||||||
                                            <span>集合</span>
 | 
					 | 
				
			||||||
                                            <el-icon v-show="state.loading[inst.id + db.Name]" class="is-loading">
 | 
					 | 
				
			||||||
                                                <Loading />
 | 
					 | 
				
			||||||
                                            </el-icon>
 | 
					 | 
				
			||||||
                                        </div>
 | 
					 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                    <el-menu-item :index="inst.id + db.Name + '-tableSearch'"
 | 
					 | 
				
			||||||
                                        :key="inst.id + db.Name + '-tableSearch'">
 | 
					 | 
				
			||||||
                                        <template #title>
 | 
					 | 
				
			||||||
                                                    
 | 
					 | 
				
			||||||
                                            <el-input size="small" placeholder="过滤" clearable
 | 
					 | 
				
			||||||
                                                @change="filterTableName(inst.id, db.Name)"
 | 
					 | 
				
			||||||
                                                @keyup="(e: any) => filterTableName(inst.id, db.Name, e)"
 | 
					 | 
				
			||||||
                                                v-model="state.filterParam[inst.id + db.Name]" />
 | 
					 | 
				
			||||||
                                        </template>
 | 
					 | 
				
			||||||
                                    </el-menu-item>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                    <template v-for="tb in instances.tables[inst.id + db.Name]">
 | 
					                        <template v-for="tb in instances.tables[inst.id + db.Name]">
 | 
				
			||||||
                                        <el-menu-item :index="inst.id + db.Name + tb.tableName"
 | 
					                            <el-menu-item :index="inst.id + db.Name + tb.tableName"
 | 
				
			||||||
                                            :key="inst.id + db.Name + tb.tableName" v-if="tb.show"
 | 
					                                :key="inst.id + db.Name + tb.tableName" v-if="tb.show"
 | 
				
			||||||
                                            @click="loadTableData(inst, db.Name, tb.tableName)">
 | 
					                                @click="loadTableData(inst, db.Name, tb.tableName)">
 | 
				
			||||||
                                            <template #title>
 | 
					                                <template #title>
 | 
				
			||||||
                                                <div style="width: 100%">
 | 
					                                    <div style="width: 100%">
 | 
				
			||||||
                                                           <el-icon>
 | 
					                                               <el-icon>
 | 
				
			||||||
                                                        <Calendar color="#409eff" />
 | 
					                                            <Calendar color="#409eff" />
 | 
				
			||||||
                                                    </el-icon>
 | 
					                                        </el-icon>
 | 
				
			||||||
                                                    <span :title="tb.tableComment || ''">{{ tb.tableName }}</span>
 | 
					                                        <span :title="tb.tableComment || ''">{{ tb.tableName }}</span>
 | 
				
			||||||
                                                </div>
 | 
					                                    </div>
 | 
				
			||||||
                                            </template>
 | 
					                                </template>
 | 
				
			||||||
                                        </el-menu-item>
 | 
					                            </el-menu-item>
 | 
				
			||||||
                                    </template>
 | 
					                        </template>
 | 
				
			||||||
                                </el-sub-menu>
 | 
					 | 
				
			||||||
                            </el-sub-menu>
 | 
					 | 
				
			||||||
                        </el-sub-menu>
 | 
					 | 
				
			||||||
                    </el-sub-menu>
 | 
					                    </el-sub-menu>
 | 
				
			||||||
                </el-menu>
 | 
					                </el-sub-menu>
 | 
				
			||||||
            </el-col>
 | 
					            </el-sub-menu>
 | 
				
			||||||
        </el-row>
 | 
					        </template>
 | 
				
			||||||
    </div>
 | 
					    </tag-menu>
 | 
				
			||||||
</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
 | 
				
			||||||
@@ -144,8 +123,8 @@ const initLoadInstances = () => {
 | 
				
			|||||||
 * @param inst 选中的实例对象
 | 
					 * @param inst 选中的实例对象
 | 
				
			||||||
 * @param fn 选中的实例对象后的回调事件
 | 
					 * @param fn 选中的实例对象后的回调事件
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const changeInstance = (inst : any, fn: Function) => {
 | 
					const changeInstance = (inst: any, fn: Function) => {
 | 
				
			||||||
  emits('changeInstance', inst, fn)
 | 
					    emits('changeInstance', inst, fn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 改变选中的数据库schema
 | 
					 * 改变选中的数据库schema
 | 
				
			||||||
@@ -164,7 +143,7 @@ const changeSchema = (inst: any, schema: string) => {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
const loadTableNames = async (inst: any, schema: string, fn: Function) => {
 | 
					const loadTableNames = async (inst: any, schema: string, fn: Function) => {
 | 
				
			||||||
    state.loading[inst.id + schema] = true
 | 
					    state.loading[inst.id + schema] = true
 | 
				
			||||||
    await emits('loadTableNames', inst, schema, (res: any)=>{
 | 
					    await emits('loadTableNames', inst, schema, (res: any) => {
 | 
				
			||||||
        state.loading[inst.id + schema] = false
 | 
					        state.loading[inst.id + schema] = false
 | 
				
			||||||
        fn && fn(res)
 | 
					        fn && fn(res)
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@@ -192,80 +171,40 @@ const filterTableName = (instId: number, schema: string, event?: any) => {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const selectDb = async (val?: any) => {
 | 
					const selectDb = async (val?: any) => {
 | 
				
			||||||
  let info = val || store.state.mongoDbOptInfo.dbOptInfo;
 | 
					    let info = val || store.state.mongoDbOptInfo.dbOptInfo;
 | 
				
			||||||
  if (info && info.dbId) {
 | 
					    if (info && info.dbId) {
 | 
				
			||||||
    const {tagPath, dbId, db} = info
 | 
					        const { tagPath, dbId, db } = info
 | 
				
			||||||
    menuRef.value.open(tagPath);
 | 
					        menuRef.value.open(tagPath);
 | 
				
			||||||
    menuRef.value.open('mongo-instance-' + dbId);
 | 
					        menuRef.value.open('mongo-instance-' + dbId);
 | 
				
			||||||
    await changeInstance({id: dbId}, () => {
 | 
					        await changeInstance({ id: dbId }, () => {
 | 
				
			||||||
      // 加载数据库
 | 
					            // 加载数据库
 | 
				
			||||||
      nextTick(async () => {
 | 
					            nextTick(async () => {
 | 
				
			||||||
        menuRef.value.open(dbId + db)
 | 
					                menuRef.value.open(dbId + db)
 | 
				
			||||||
        // 加载集合列表
 | 
					                // 加载集合列表
 | 
				
			||||||
        await nextTick(async () => {
 | 
					                await nextTick(async () => {
 | 
				
			||||||
          await loadTableNames({id: dbId}, db, (res: any[]) => {
 | 
					                    await loadTableNames({ id: dbId }, db, (res: any[]) => {
 | 
				
			||||||
            // 展开集合列表
 | 
					                        // 展开集合列表
 | 
				
			||||||
            menuRef.value.open(dbId + db + '-table')
 | 
					                        menuRef.value.open(dbId + db + '-table')
 | 
				
			||||||
            // 加载第一张集合数据
 | 
					                        // 加载第一张集合数据
 | 
				
			||||||
            loadTableData({id: dbId}, db, res[0].tableName)
 | 
					                        loadTableData({ id: dbId }, db, res[0].tableName)
 | 
				
			||||||
          })
 | 
					                    })
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      })
 | 
					    }
 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(()=>{
 | 
					onMounted(() => {
 | 
				
			||||||
  selectDb();
 | 
					    selectDb();
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(()=>store.state.mongoDbOptInfo.dbOptInfo, async newValue => {
 | 
					watch(() => store.state.mongoDbOptInfo.dbOptInfo, async newValue => {
 | 
				
			||||||
  await selectDb(newValue)
 | 
					    await selectDb(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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,72 +1,66 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <el-card>
 | 
					        <el-row>
 | 
				
			||||||
          <el-row>
 | 
					            <el-col :span="4">
 | 
				
			||||||
            <el-col :span="3">
 | 
					                <redis-instance-tree @init-load-instances="initLoadInstances" @change-instance="changeInstance"
 | 
				
			||||||
              <redis-instance-tree 
 | 
					                    @change-schema="loadInitSchema" :instances="state.instances" />
 | 
				
			||||||
                  @init-load-instances="initLoadInstances"
 | 
					 | 
				
			||||||
                  @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">
 | 
				
			||||||
                    <el-input placeholder="match 支持*模糊key" style="width: 250px" v-model="scanParam.match"
 | 
					                            <el-input placeholder="match 支持*模糊key" style="width: 250px" v-model="scanParam.match"
 | 
				
			||||||
                              @clear="clear()" clearable></el-input>
 | 
					                                @clear="clear()" clearable></el-input>
 | 
				
			||||||
                  </el-form-item>
 | 
					                        </el-form-item>
 | 
				
			||||||
                  <el-form-item label="count" label-width="40px">
 | 
					                        <el-form-item label="count" label-width="40px">
 | 
				
			||||||
                    <el-input placeholder="count" style="width: 70px" v-model.number="scanParam.count">
 | 
					                            <el-input placeholder="count" style="width: 70px" v-model.number="scanParam.count">
 | 
				
			||||||
                    </el-input>
 | 
					                            </el-input>
 | 
				
			||||||
                  </el-form-item>
 | 
					                        </el-form-item>
 | 
				
			||||||
                  <el-form-item>
 | 
					                        <el-form-item>
 | 
				
			||||||
                    <el-button @click="searchKey()" type="success" icon="search" plain></el-button>
 | 
					                            <el-button @click="searchKey()" type="success" icon="search" plain></el-button>
 | 
				
			||||||
                    <el-button @click="scan()" icon="bottom" plain>scan</el-button>
 | 
					                            <el-button @click="scan()" icon="bottom" plain>scan</el-button>
 | 
				
			||||||
                    <el-popover placement="right" :width="200" trigger="click">
 | 
					                            <el-popover placement="right" :width="200" trigger="click">
 | 
				
			||||||
                      <template #reference>
 | 
					                                <template #reference>
 | 
				
			||||||
                        <el-button type="primary" icon="plus" plain></el-button>
 | 
					                                    <el-button type="primary" icon="plus" plain></el-button>
 | 
				
			||||||
                      </template>
 | 
					                                </template>
 | 
				
			||||||
                      <el-tag @click="onAddData('string')" :color="getTypeColor('string')"
 | 
					                                <el-tag @click="onAddData('string')" :color="getTypeColor('string')"
 | 
				
			||||||
                              style="cursor: pointer">string</el-tag>
 | 
					                                    style="cursor: pointer">string</el-tag>
 | 
				
			||||||
                      <el-tag @click="onAddData('hash')" :color="getTypeColor('hash')" class="ml5"
 | 
					                                <el-tag @click="onAddData('hash')" :color="getTypeColor('hash')" class="ml5"
 | 
				
			||||||
                              style="cursor: pointer">hash</el-tag>
 | 
					                                    style="cursor: pointer">hash</el-tag>
 | 
				
			||||||
                      <el-tag @click="onAddData('set')" :color="getTypeColor('set')" class="ml5"
 | 
					                                <el-tag @click="onAddData('set')" :color="getTypeColor('set')" class="ml5"
 | 
				
			||||||
                              style="cursor: pointer">set</el-tag>
 | 
					                                    style="cursor: pointer">set</el-tag>
 | 
				
			||||||
                      <!-- <el-tag @click="onAddData('list')" :color="getTypeColor('list')" class="ml5" style="cursor: pointer">list</el-tag> -->
 | 
					                                <!-- <el-tag @click="onAddData('list')" :color="getTypeColor('list')" class="ml5" style="cursor: pointer">list</el-tag> -->
 | 
				
			||||||
                    </el-popover>
 | 
					                            </el-popover>
 | 
				
			||||||
                  </el-form-item>
 | 
					                        </el-form-item>
 | 
				
			||||||
                  <div style="float: right">
 | 
					                        <div style="float: right">
 | 
				
			||||||
                    <span>keys: {{ state.dbsize }}</span>
 | 
					                            <span>keys: {{ state.dbsize }}</span>
 | 
				
			||||||
                  </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"
 | 
				
			||||||
                <el-table-column show-overflow-tooltip prop="key" label="key"></el-table-column>
 | 
					                    style="cursor: pointer">
 | 
				
			||||||
                <el-table-column prop="type" label="type" width="80">
 | 
					                    <el-table-column show-overflow-tooltip prop="key" label="key"></el-table-column>
 | 
				
			||||||
                  <template #default="scope">
 | 
					                    <el-table-column prop="type" label="type" width="80">
 | 
				
			||||||
                    <el-tag :color="getTypeColor(scope.row.type)" size="small">{{ scope.row.type }}</el-tag>
 | 
					                        <template #default="scope">
 | 
				
			||||||
                  </template>
 | 
					                            <el-tag :color="getTypeColor(scope.row.type)" size="small">{{ scope.row.type }}</el-tag>
 | 
				
			||||||
                </el-table-column>
 | 
					                        </template>
 | 
				
			||||||
                <el-table-column prop="ttl" label="ttl(过期时间)" width="140">
 | 
					                    </el-table-column>
 | 
				
			||||||
                  <template #default="scope">
 | 
					                    <el-table-column prop="ttl" label="ttl(过期时间)" width="140">
 | 
				
			||||||
                    {{ ttlConveter(scope.row.ttl) }}
 | 
					                        <template #default="scope">
 | 
				
			||||||
                  </template>
 | 
					                            {{ ttlConveter(scope.row.ttl) }}
 | 
				
			||||||
                </el-table-column>
 | 
					                        </template>
 | 
				
			||||||
                <el-table-column label="操作">
 | 
					                    </el-table-column>
 | 
				
			||||||
                  <template #default="scope">
 | 
					                    <el-table-column label="操作">
 | 
				
			||||||
                    <el-button @click="getValue(scope.row)" type="success" icon="search" plain size="small">查看
 | 
					                        <template #default="scope">
 | 
				
			||||||
                    </el-button>
 | 
					                            <el-button @click="getValue(scope.row)" type="success" icon="search" plain size="small">查看
 | 
				
			||||||
                    <el-button @click="del(scope.row.key)" type="danger" icon="delete" plain size="small">删除
 | 
					                            </el-button>
 | 
				
			||||||
                    </el-button>
 | 
					                            <el-button @click="del(scope.row.key)" type="danger" icon="delete" plain size="small">删除
 | 
				
			||||||
                  </template>
 | 
					                            </el-button>
 | 
				
			||||||
                </el-table-column>
 | 
					                        </template>
 | 
				
			||||||
              </el-table>
 | 
					                    </el-table-column>
 | 
				
			||||||
 | 
					                </el-table>
 | 
				
			||||||
            </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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,7 +136,7 @@ const state = reactive({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    keys: [],
 | 
					    keys: [],
 | 
				
			||||||
    dbsize: 0,
 | 
					    dbsize: 0,
 | 
				
			||||||
    instances:{tags:{}, tree:{}, dbs:{}, tables:{}}
 | 
					    instances: { tags: {}, tree: {}, dbs: {}, tables: {} }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
@@ -257,16 +251,16 @@ const del = (key: string) => {
 | 
				
			|||||||
        cancelButtonText: '取消',
 | 
					        cancelButtonText: '取消',
 | 
				
			||||||
        type: 'warning',
 | 
					        type: 'warning',
 | 
				
			||||||
    }).then(() => {
 | 
					    }).then(() => {
 | 
				
			||||||
      redisApi.delKey
 | 
					        redisApi.delKey
 | 
				
			||||||
          .request({
 | 
					            .request({
 | 
				
			||||||
            key,
 | 
					                key,
 | 
				
			||||||
            id: state.scanParam.id,
 | 
					                id: state.scanParam.id,
 | 
				
			||||||
            db: state.scanParam.db,
 | 
					                db: state.scanParam.db,
 | 
				
			||||||
          })
 | 
					            })
 | 
				
			||||||
          .then(() => {
 | 
					            .then(() => {
 | 
				
			||||||
            ElMessage.success('删除成功!');
 | 
					                ElMessage.success('删除成功!');
 | 
				
			||||||
            searchKey();
 | 
					                searchKey();
 | 
				
			||||||
          });
 | 
					            });
 | 
				
			||||||
    }).catch(() => { });
 | 
					    }).catch(() => { });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -319,43 +313,43 @@ const getTypeColor = (type: string) => {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const initLoadInstances = async ()=>{
 | 
					const initLoadInstances = async () => {
 | 
				
			||||||
  const res = await redisApi.redisList.request({});
 | 
					    const res = await redisApi.redisList.request({});
 | 
				
			||||||
  if(!res.total) return
 | 
					    if (!res.total) return
 | 
				
			||||||
  state.instances = {tags:{}, tree:{}, dbs:{}, tables:{}} ; // 初始化变量
 | 
					    state.instances = { tags: {}, tree: {}, dbs: {}, tables: {} }; // 初始化变量
 | 
				
			||||||
  for (const db of res.list) {
 | 
					    for (const db of res.list) {
 | 
				
			||||||
    let arr = state.instances.tree[db.tagId] || []
 | 
					        let arr = state.instances.tree[db.tagId] || []
 | 
				
			||||||
    const {tagId, tagPath} = db
 | 
					        const { tagId, tagPath } = db
 | 
				
			||||||
    // tags
 | 
					        // tags
 | 
				
			||||||
    state.instances.tags[db.tagId]={tagId, tagPath}
 | 
					        state.instances.tags[db.tagId] = { tagId, tagPath }
 | 
				
			||||||
    // 实例
 | 
					        // 实例
 | 
				
			||||||
    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){
 | 
					    const res = await redisApi.redisInfo.request({ id: inst.id, host: inst.host, section: "Keyspace" });
 | 
				
			||||||
      dbs.push({
 | 
					    for (let db in res.Keyspace) {
 | 
				
			||||||
        name: db,
 | 
					        for (let d of dbs) {
 | 
				
			||||||
        keys: res.Keyspace[db]?.split(',')[0]?.split('=')[1] || 0
 | 
					            if (db == d.name) {
 | 
				
			||||||
      })
 | 
					                d.keys = res.Keyspace[db]?.split(',')[0]?.split('=')[1] || 0
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  state.instances.dbs[inst.id] = dbs
 | 
					    state.instances.dbs[inst.id] = dbs
 | 
				
			||||||
  fn && fn(dbs)
 | 
					    fn && fn(dbs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** 初始化加载db数据 */
 | 
					/** 初始化加载db数据 */
 | 
				
			||||||
const loadInitSchema = (inst: any, schema: string)=>{
 | 
					const loadInitSchema = (inst: any, schema: string) => {
 | 
				
			||||||
  state.scanParam.id = inst.id
 | 
					    state.scanParam.id = inst.id
 | 
				
			||||||
  state.scanParam.db = schema.replace('db','')
 | 
					    state.scanParam.db = schema.replace('db', '')
 | 
				
			||||||
  scan()
 | 
					    scan()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,100 +1,78 @@
 | 
				
			|||||||
<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>
 | 
					 | 
				
			||||||
              <el-icon><FolderOpened color="#e6a23c"/></el-icon>
 | 
					 | 
				
			||||||
              <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>
 | 
					 | 
				
			||||||
                    <span>  <el-icon><MostlyCloudy color="#409eff"/></el-icon>{{ inst.name }}</span>
 | 
					 | 
				
			||||||
                  </template>
 | 
					 | 
				
			||||||
                  <template #default>
 | 
					 | 
				
			||||||
                    <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.host}}</el-form-item>
 | 
					 | 
				
			||||||
                    </el-form>
 | 
					 | 
				
			||||||
                  </template>
 | 
					 | 
				
			||||||
                </el-popover>
 | 
					 | 
				
			||||||
              </template>
 | 
					 | 
				
			||||||
              <!-- 第三级:数据库 -->
 | 
					 | 
				
			||||||
              <el-sub-menu v-for="db in instances.dbs[inst.id]" 
 | 
					 | 
				
			||||||
                           :index="inst.id + db.name" 
 | 
					 | 
				
			||||||
                           :key="inst.id + db.name"
 | 
					 | 
				
			||||||
                           :class="state.nowSchema === (inst.id+db.name) && 'checked'"
 | 
					 | 
				
			||||||
                           @click.prevent="changeSchema(inst, db.name)"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <template #title>
 | 
					                <template #title>
 | 
				
			||||||
                      <el-icon><Coin color="#67c23a"/></el-icon>
 | 
					                    <el-popover placement="right-start" title="redis实例信息" trigger="hover" :width="210">
 | 
				
			||||||
                  <span class="checked-schema">
 | 
					                        <template #reference>
 | 
				
			||||||
                    {{ db.name  }} [{{db.keys}}]
 | 
					                            <span>  <el-icon>
 | 
				
			||||||
                  </span>
 | 
					                                    <MostlyCloudy color="#409eff" />
 | 
				
			||||||
 | 
					                                </el-icon>{{ inst.name }}</span>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                        <template #default>
 | 
				
			||||||
 | 
					                            <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.host }}</el-form-item>
 | 
				
			||||||
 | 
					                                <el-form-item label="备注:">{{ inst.remark }}</el-form-item>
 | 
				
			||||||
 | 
					                            </el-form>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                    </el-popover>
 | 
				
			||||||
                </template>
 | 
					                </template>
 | 
				
			||||||
              </el-sub-menu>
 | 
					                <!-- 第三级:数据库 -->
 | 
				
			||||||
 | 
					                <el-menu-item v-for="db in instances.dbs[inst.id]" :index="inst.id + db.name" :key="inst.id + db.name"
 | 
				
			||||||
 | 
					                    :class="state.nowSchema === (inst.id + db.name) && 'checked'"
 | 
				
			||||||
 | 
					                    @click="changeSchema(inst, db.name)">
 | 
				
			||||||
 | 
					                    <template #title>
 | 
				
			||||||
 | 
					                            <el-icon>
 | 
				
			||||||
 | 
					                            <Coin color="#67c23a" />
 | 
				
			||||||
 | 
					                        </el-icon>
 | 
				
			||||||
 | 
					                        <span class="checked-schema">
 | 
				
			||||||
 | 
					                            {{ db.name }} [{{ db.keys }}]
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-menu-item>
 | 
				
			||||||
            </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 {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: {
 | 
				
			||||||
    type: Object, required: true
 | 
					        type: Object, required: true
 | 
				
			||||||
  },
 | 
					    },
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const emits = defineEmits(['initLoadInstances','changeInstance','changeSchema'])
 | 
					const emits = defineEmits(['initLoadInstances', 'changeInstance', 'changeSchema'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onBeforeMount(async ()=>{
 | 
					onBeforeMount(async () => {
 | 
				
			||||||
  await initLoadInstances()
 | 
					    await initLoadInstances()
 | 
				
			||||||
  setHeight()
 | 
					    setHeight()
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state = reactive({
 | 
					const state = reactive({
 | 
				
			||||||
  instanceMenuMaxHeight: '800px',
 | 
					    instanceMenuMaxHeight: '800px',
 | 
				
			||||||
  nowSchema: '',
 | 
					    nowSchema: '',
 | 
				
			||||||
  filterParam: {},
 | 
					    filterParam: {},
 | 
				
			||||||
  loading: {},
 | 
					    loading: {},
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 初始化加载实例数据
 | 
					 * 初始化加载实例数据
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const initLoadInstances = () => {
 | 
					const initLoadInstances = () => {
 | 
				
			||||||
  emits('initLoadInstances')
 | 
					    emits('initLoadInstances')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -102,78 +80,45 @@ const initLoadInstances = () => {
 | 
				
			|||||||
 * @param inst 选中的实例对象
 | 
					 * @param inst 选中的实例对象
 | 
				
			||||||
 * @param fn 选中的实例后的回调函数
 | 
					 * @param fn 选中的实例后的回调函数
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const changeInstance = (inst : any, fn?:Function) => {
 | 
					const changeInstance = (inst: any, fn?: Function) => {
 | 
				
			||||||
  emits('changeInstance', inst, fn)
 | 
					    emits('changeInstance', inst, fn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 改变选中的数据库schema
 | 
					 * 改变选中的数据库schema
 | 
				
			||||||
 * @param inst 选中的实例对象
 | 
					 * @param inst 选中的实例对象
 | 
				
			||||||
 * @param schema 选中的数据库schema
 | 
					 * @param schema 选中的数据库schema
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const changeSchema = (inst : any, schema: string) => {
 | 
					const changeSchema = (inst: any, schema: string) => {
 | 
				
			||||||
  state.nowSchema = inst.id + schema
 | 
					    state.nowSchema = inst.id + schema
 | 
				
			||||||
  emits('changeSchema', inst, schema)
 | 
					    emits('changeSchema', inst, schema)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const selectDb = async (val?: any) => {
 | 
					const selectDb = async (val?: any) => {
 | 
				
			||||||
  const info = val || store.state.redisDbOptInfo.dbOptInfo
 | 
					    const info = val || store.state.redisDbOptInfo.dbOptInfo
 | 
				
			||||||
  if (info && info.dbId) {
 | 
					    if (info && info.dbId) {
 | 
				
			||||||
    const {tagPath, dbId} = info
 | 
					        const { tagPath, dbId } = info
 | 
				
			||||||
    menuRef.value.open(tagPath);
 | 
					        menuRef.value.open(tagPath);
 | 
				
			||||||
    menuRef.value.open('redis-instance-' + dbId);
 | 
					        menuRef.value.open('redis-instance-' + dbId);
 | 
				
			||||||
    await changeInstance({id: dbId}, async (dbs: any[]) => {
 | 
					        await changeInstance({ id: dbId }, async (dbs: any[]) => {
 | 
				
			||||||
      await changeSchema({id: dbId}, dbs[0]?.name)
 | 
					            await changeSchema({ id: dbId }, dbs[0]?.name)
 | 
				
			||||||
    })
 | 
					        })
 | 
				
			||||||
  }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(()=>{
 | 
					onMounted(() => {
 | 
				
			||||||
  selectDb();
 | 
					    selectDb();
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(()=>store.state.redisDbOptInfo.dbOptInfo, async newValue =>{
 | 
					watch(() => store.state.redisDbOptInfo.dbOptInfo, async newValue => {
 | 
				
			||||||
  await selectDb(newValue)
 | 
					    await selectDb(newValue)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
.instances-box {
 | 
					.instances-pop-form {
 | 
				
			||||||
  .el-menu{
 | 
					    .el-form-item {
 | 
				
			||||||
    width: 275px;
 | 
					        margin-bottom: unset;
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  .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>
 | 
					</style>
 | 
				
			||||||
@@ -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")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user