Files
mayfly-go/mayfly_go_web/src/views/ops/db/component/InstanceTree.vue

289 lines
12 KiB
Vue
Raw Normal View History

2023-01-31 10:37:40 +08:00
<template>
2023-02-06 17:14:16 +08:00
<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" ref="menuRef">
2023-02-06 17:14:16 +08:00
<!-- 第一级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, ()=>{})">
2023-02-06 17:14:16 +08:00
<template #title>
<el-popover placement="right-start" title="数据库实例信息" trigger="hover" :width="210">
<template #reference>
<span>&nbsp;&nbsp;<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>
&nbsp;&nbsp;&nbsp;&nbsp;<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, ()=>{})">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<el-icon>
<Calendar color="#409eff"/>
2023-02-06 17:14:16 +08:00
</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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<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>
2023-01-31 10:37:40 +08:00
2023-02-06 17:14:16 +08:00
<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%">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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>
<!-- 第四级 02sql -->
<el-sub-menu :index="inst.id + schema + '-sql'">
<template #title>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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%">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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>
2023-01-31 10:37:40 +08:00
</template>
<script lang="ts" setup>
2023-02-07 10:32:42 +08:00
import {nextTick, onBeforeMount, onMounted, reactive, ref, Ref, watch} from 'vue';
import {store} from '@/store';
2023-01-31 10:37:40 +08:00
const props = defineProps({
2023-02-06 17:14:16 +08:00
instanceMenuMaxHeight: {
type: [Number, String],
},
instances: {
type: Object, required: true
},
2023-01-31 10:37:40 +08:00
})
2023-02-06 17:14:16 +08:00
const emits = defineEmits(['initLoadInstances', 'changeInstance', 'loadTableNames', 'loadTableData', 'changeSchema'])
2023-01-31 10:37:40 +08:00
2023-02-06 17:14:16 +08:00
onBeforeMount(async () => {
await initLoadInstances()
2023-01-31 10:37:40 +08:00
})
2023-02-07 10:32:42 +08:00
const menuRef = ref(null) as Ref
2023-01-31 10:37:40 +08:00
const state = reactive({
2023-02-06 17:14:16 +08:00
nowSchema: '',
filterParam: {},
loading: {}
2023-01-31 10:37:40 +08:00
})
/**
* 初始化加载实例数据
*/
const initLoadInstances = () => {
2023-02-06 17:14:16 +08:00
emits('initLoadInstances')
2023-01-31 10:37:40 +08:00
}
/**
* 改变选中的数据库实例
* @param inst 选中的实例对象
2023-02-07 10:32:42 +08:00
* @param fn 选中的实例对象后的回调函数
2023-01-31 10:37:40 +08:00
*/
2023-02-07 10:32:42 +08:00
const changeInstance = (inst : any, fn: Function) => {
emits('changeInstance', inst, fn)
2023-01-31 10:37:40 +08:00
}
/**
* 改变选中的数据库schema
* @param inst 选中的实例对象
* @param schema 选中的数据库schema
*/
2023-02-06 17:14:16 +08:00
const changeSchema = (inst: any, schema: string) => {
state.nowSchema = inst.id + schema
emits('changeSchema', inst, schema)
2023-01-31 10:37:40 +08:00
}
/**
* 加载schema下所有表
* @param inst 数据库实例
* @param schema database名
2023-02-07 10:32:42 +08:00
* @param fn 加载表集合后的回调函数参数res 表集合
2023-01-31 10:37:40 +08:00
*/
2023-02-07 10:32:42 +08:00
const loadTableNames = async (inst: any, schema: string, fn: Function) => {
2023-02-06 17:14:16 +08:00
state.loading[inst.id + schema] = true
2023-02-07 10:32:42 +08:00
await emits('loadTableNames', inst, schema, (res: any[])=>{
2023-02-06 17:14:16 +08:00
state.loading[inst.id + schema] = false
2023-02-07 10:32:42 +08:00
fn && fn(res)
2023-02-06 17:14:16 +08:00
})
2023-01-31 10:37:40 +08:00
}
/**
* 加载选中表数据
* @param inst 数据库实例
* @param schema database名
* @param tableName 表名
*/
const loadTableData = (inst: any, schema: string, tableName: string) => {
2023-02-06 17:14:16 +08:00
emits('loadTableData', inst, schema, tableName)
2023-01-31 10:37:40 +08:00
}
const filterTableName = (instId: number, schema: string, event?: any) => {
2023-02-06 17:14:16 +08:00
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
})
2023-01-31 10:37:40 +08:00
}
2023-02-07 10:32:42 +08:00
const selectDb = async (val?: any) => {
let info = val || store.state.sqlExecInfo.dbOptInfo;
if (info && info.dbId) {
const {tagPath, dbId, db} = info
menuRef.value.open(tagPath);
menuRef.value.open('instance-' + dbId);
await changeInstance({id: dbId}, () => {
// 加载数据库
nextTick(async () => {
menuRef.value.open(dbId + db)
state.nowSchema = (dbId+db)
// 加载集合列表
await nextTick(async () => {
await loadTableNames({id: dbId}, db, (res: any[]) => {
// 展开集合列表
menuRef.value.open(dbId + db + '-table')
console.log(res)
})
})
})
})
}
}
onMounted(()=>{
selectDb();
})
watch(()=>store.state.sqlExecInfo.dbOptInfo, async newValue => {
await selectDb(newValue)
})
2023-01-31 10:37:40 +08:00
</script>
<style lang="scss">
.instances-box {
2023-02-06 17:14:16 +08:00
.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;
2023-01-31 10:37:40 +08:00
}
}
2023-02-06 17:14:16 +08:00
.instances-pop-form {
.el-form-item {
margin-bottom: unset;
}
2023-01-31 10:37:40 +08:00
}
</style>