mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 23:40:24 +08:00
feat: 数据管理添加实例树
This commit is contained in:
File diff suppressed because it is too large
Load Diff
231
mayfly_go_web/src/views/ops/db/component/InstanceTree.vue
Normal file
231
mayfly_go_web/src/views/ops/db/component/InstanceTree.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<div class="instances-box layout-aside">
|
||||
<el-row type="flex" justify="space-between">
|
||||
<el-col :span="24" :style="{maxHeight: instanceMenuMaxHeight, overflow:'auto'}" class="el-scrollbar flex-auto">
|
||||
<el-menu background-color="transparent">
|
||||
<!-- 第一级: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"
|
||||
:key="'instance-' + inst.id"
|
||||
@click="changeInstance(inst)"
|
||||
>
|
||||
<template #title>
|
||||
<el-popover
|
||||
placement="right-start"
|
||||
title="数据库实例信息"
|
||||
trigger="hover"
|
||||
:width="180"
|
||||
>
|
||||
<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.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="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>
|
||||
</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 => 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>
|
||||
<span :title="tb.tableComment||''">{{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>
|
||||
<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>
|
||||
</el-sub-menu>
|
||||
</el-menu>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {onBeforeMount, reactive} from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
instanceMenuMaxHeight: {
|
||||
type: [Number, String],
|
||||
},
|
||||
instances: {
|
||||
type: Object, required: true
|
||||
},
|
||||
})
|
||||
|
||||
const emits = defineEmits(['initLoadInstances','changeInstance','loadTableNames','loadTableData','changeSchema'])
|
||||
|
||||
onBeforeMount(async ()=>{
|
||||
await initLoadInstances()
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
nowSchema:'',
|
||||
filterParam: {}
|
||||
})
|
||||
|
||||
/**
|
||||
* 初始化加载实例数据
|
||||
*/
|
||||
const initLoadInstances = () => {
|
||||
emits('initLoadInstances')
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变选中的数据库实例
|
||||
* @param inst 选中的实例对象
|
||||
*/
|
||||
const changeInstance = (inst : any) => {
|
||||
emits('changeInstance', inst)
|
||||
}
|
||||
/**
|
||||
* 改变选中的数据库schema
|
||||
* @param inst 选中的实例对象
|
||||
* @param schema 选中的数据库schema
|
||||
*/
|
||||
const changeSchema = (inst : any, schema: string) => {
|
||||
state.nowSchema = inst.id + schema
|
||||
emits('changeSchema', inst, schema)
|
||||
}
|
||||
/**
|
||||
* 加载schema下所有表
|
||||
* @param inst 数据库实例
|
||||
* @param schema database名
|
||||
*/
|
||||
const loadTableNames = (inst: any, schema: string) => {
|
||||
emits('loadTableNames', inst, schema)
|
||||
}
|
||||
/**
|
||||
* 加载选中表数据
|
||||
* @param inst 数据库实例
|
||||
* @param schema database名
|
||||
* @param tableName 表名
|
||||
*/
|
||||
const loadTableData = (inst: any, schema: string, tableName: string) => {
|
||||
emits('loadTableData', inst, schema, tableName)
|
||||
}
|
||||
|
||||
const filterTableName = (instId: number, schema: string, event?: any) => {
|
||||
if(event){
|
||||
state.filterParam[instId+schema] = event.target.value
|
||||
}
|
||||
let param = state.filterParam[instId+schema] as string
|
||||
param = param?.replace('/','\/')
|
||||
const key = instId + schema;
|
||||
props.instances.tables[key].forEach((a:any) =>{
|
||||
a.show = param?eval('/'+param.split('').join('[_\w]*')+'[_\w]*/ig').test(a.tableName):true
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.instances-box {
|
||||
.el-menu{
|
||||
width: 210px;
|
||||
}
|
||||
.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>
|
||||
Reference in New Issue
Block a user