mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-12 20:30:25 +08:00
refactor: 界面优化
This commit is contained in:
File diff suppressed because one or more lines are too long
135
mayfly_go_web/src/components/contextmenu/index.vue
Normal file
135
mayfly_go_web/src/components/contextmenu/index.vue
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<template>
|
||||||
|
<transition name="el-zoom-in-center">
|
||||||
|
<div aria-hidden="true" class="el-dropdown__popper el-popper is-light is-pure custom-contextmenu" role="tooltip"
|
||||||
|
data-popper-placement="bottom" :style="`top: ${dropdowns.y + 5}px;left: ${dropdowns.x}px;`" :key="Math.random()"
|
||||||
|
v-show="state.isShow">
|
||||||
|
<ul class="el-dropdown-menu">
|
||||||
|
<template v-for="(v, k) in state.dropdownList">
|
||||||
|
<li class="el-dropdown-menu__item" aria-disabled="false" tabindex="-1" :key="k" v-if="!v.affix"
|
||||||
|
@click="onCurrentContextmenuClick(v.contextMenuClickId)">
|
||||||
|
<SvgIcon :name="v.icon" />
|
||||||
|
<span>{{ v.txt }}</span>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
<div class="el-popper__arrow" :style="{ left: `${state.arrowLeft}px` }"></div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="layoutTagsViewContextmenu">
|
||||||
|
import { computed, reactive, onMounted, onUnmounted, watch } from 'vue';
|
||||||
|
|
||||||
|
// 定义父组件传过来的值
|
||||||
|
const props = defineProps({
|
||||||
|
dropdown: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['currentContextmenuClick']);
|
||||||
|
|
||||||
|
// 定义变量内容
|
||||||
|
const state = reactive({
|
||||||
|
isShow: false,
|
||||||
|
dropdownList: [
|
||||||
|
{ contextMenuClickId: 0, txt: '刷新', affix: false, icon: 'RefreshRight' },
|
||||||
|
{ contextMenuClickId: 1, txt: '关闭', affix: false, icon: 'Close' },
|
||||||
|
{ contextMenuClickId: 2, txt: '关闭其他', affix: false, icon: 'CircleClose' },
|
||||||
|
{ contextMenuClickId: 3, txt: '关闭所有', affix: false, icon: 'FolderDelete' },
|
||||||
|
],
|
||||||
|
item: {} as any,
|
||||||
|
arrowLeft: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 父级传过来的坐标 x,y 值
|
||||||
|
const dropdowns = computed(() => {
|
||||||
|
// 117 为 `Dropdown 下拉菜单` 的宽度
|
||||||
|
if (props.dropdown.x + 117 > document.documentElement.clientWidth) {
|
||||||
|
return {
|
||||||
|
x: document.documentElement.clientWidth - 117 - 5,
|
||||||
|
y: props.dropdown.y,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return props.dropdown;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 当前项菜单点击
|
||||||
|
const onCurrentContextmenuClick = (contextMenuClickId: number) => {
|
||||||
|
emit('currentContextmenuClick', { id: contextMenuClickId, item: state.item });
|
||||||
|
};
|
||||||
|
// 打开右键菜单:判断是否固定,固定则不显示关闭按钮
|
||||||
|
const openContextmenu = (item: any) => {
|
||||||
|
state.item = item;
|
||||||
|
closeContextmenu();
|
||||||
|
setTimeout(() => {
|
||||||
|
state.isShow = true;
|
||||||
|
}, 10);
|
||||||
|
};
|
||||||
|
// 关闭右键菜单
|
||||||
|
const closeContextmenu = () => {
|
||||||
|
state.isShow = false;
|
||||||
|
};
|
||||||
|
// 监听页面监听进行右键菜单的关闭
|
||||||
|
onMounted(() => {
|
||||||
|
document.body.addEventListener('click', closeContextmenu);
|
||||||
|
});
|
||||||
|
// 页面卸载时,移除右键菜单监听事件
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.body.removeEventListener('click', closeContextmenu);
|
||||||
|
});
|
||||||
|
// 监听下拉菜单位置
|
||||||
|
watch(
|
||||||
|
() => props.dropdown,
|
||||||
|
({ x }) => {
|
||||||
|
if (x + 117 > document.documentElement.clientWidth) state.arrowLeft = 117 - (document.documentElement.clientWidth - x);
|
||||||
|
else state.arrowLeft = 10;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => props.items,
|
||||||
|
(x: any) => {
|
||||||
|
state.dropdownList = x
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 暴露变量
|
||||||
|
defineExpose({
|
||||||
|
openContextmenu,
|
||||||
|
closeContextmenu,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.custom-contextmenu {
|
||||||
|
transform-origin: center top;
|
||||||
|
z-index: 2190;
|
||||||
|
position: fixed;
|
||||||
|
|
||||||
|
.el-dropdown-menu__item {
|
||||||
|
font-size: 12px !important;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -7,66 +7,86 @@
|
|||||||
data-popper-placement="bottom"
|
data-popper-placement="bottom"
|
||||||
:style="`top: ${dropdowns.y + 5}px;left: ${dropdowns.x}px;`"
|
:style="`top: ${dropdowns.y + 5}px;left: ${dropdowns.x}px;`"
|
||||||
:key="Math.random()"
|
:key="Math.random()"
|
||||||
v-show="isShow"
|
v-show="state.isShow"
|
||||||
>
|
>
|
||||||
<ul class="el-dropdown-menu">
|
<ul class="el-dropdown-menu">
|
||||||
<template v-for="(v, k) in dropdownList">
|
<template v-for="(v, k) in state.dropdownList">
|
||||||
<li
|
<li
|
||||||
class="el-dropdown-menu__item"
|
class="el-dropdown-menu__item"
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
:key="k"
|
:key="k"
|
||||||
v-if="!v.affix"
|
v-if="!v.affix"
|
||||||
@click="onCurrentContextmenuClick(v.id)"
|
@click="onCurrentContextmenuClick(v.contextMenuClickId)"
|
||||||
>
|
>
|
||||||
<i :class="v.icon"></i>
|
<SvgIcon :name="v.icon" />
|
||||||
<span>{{ v.txt }}</span>
|
<span>{{ v.txt }}</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="el-popper__arrow" style="left: 10px"></div>
|
<div class="el-popper__arrow" :style="{ left: `${state.arrowLeft}px` }"></div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts" name="layoutTagsViewContextmenu">
|
||||||
import { computed, defineComponent, reactive, toRefs, onMounted, onUnmounted } from 'vue';
|
import { computed, reactive, onMounted, onUnmounted, watch } from 'vue';
|
||||||
export default defineComponent({
|
|
||||||
name: 'layoutTagsViewContextmenu',
|
// 定义父组件传过来的值
|
||||||
props: {
|
const props = defineProps({
|
||||||
dropdown: {
|
dropdown: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
});
|
||||||
|
|
||||||
|
// 定义子组件向父组件传值/事件
|
||||||
|
const emit = defineEmits(['currentContextmenuClick']);
|
||||||
|
|
||||||
|
// 定义变量内容
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isShow: false,
|
isShow: false,
|
||||||
dropdownList: [
|
dropdownList: [
|
||||||
{ id: 0, txt: '刷新', affix: false, icon: 'el-icon-refresh-right' },
|
{ contextMenuClickId: 0, txt: '刷新', affix: false, icon: 'RefreshRight' },
|
||||||
{ id: 1, txt: '关闭', affix: false, icon: 'el-icon-close' },
|
{ contextMenuClickId: 1, txt: '关闭', affix: false, icon: 'Close' },
|
||||||
{ id: 2, txt: '关闭其他', affix: false, icon: 'el-icon-circle-close' },
|
{ contextMenuClickId: 2, txt: '关闭其他', affix: false, icon: 'CircleClose' },
|
||||||
{ id: 3, txt: '关闭所有', affix: false, icon: 'el-icon-folder-delete' },
|
{ contextMenuClickId: 3, txt: '关闭所有', affix: false, icon: 'FolderDelete' },
|
||||||
{
|
{
|
||||||
id: 4,
|
contextMenuClickId: 4,
|
||||||
txt: '当前页全屏',
|
txt: '当前页全屏',
|
||||||
affix: false,
|
affix: false,
|
||||||
icon: 'el-icon-full-screen',
|
icon: 'full-screen',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
path: {},
|
item: {} as any,
|
||||||
|
arrowLeft: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 父级传过来的坐标 x,y 值
|
// 父级传过来的坐标 x,y 值
|
||||||
const dropdowns = computed(() => {
|
const dropdowns = computed(() => {
|
||||||
|
// 117 为 `Dropdown 下拉菜单` 的宽度
|
||||||
|
if (props.dropdown.x + 117 > document.documentElement.clientWidth) {
|
||||||
|
return {
|
||||||
|
x: document.documentElement.clientWidth - 117 - 5,
|
||||||
|
y: props.dropdown.y,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
return props.dropdown;
|
return props.dropdown;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// 当前项菜单点击
|
// 当前项菜单点击
|
||||||
const onCurrentContextmenuClick = (id: number) => {
|
const onCurrentContextmenuClick = (contextMenuClickId: number) => {
|
||||||
emit('currentContextmenuClick', { id, path: state.path });
|
emit('currentContextmenuClick', { id: contextMenuClickId, path: state.item.fullPath });
|
||||||
};
|
};
|
||||||
// 打开右键菜单:判断是否固定,固定则不显示关闭按钮
|
// 打开右键菜单:判断是否固定,固定则不显示关闭按钮
|
||||||
const openContextmenu = (item: any) => {
|
const openContextmenu = (item: any) => {
|
||||||
state.path = item.fullPath;
|
state.item = item;
|
||||||
item.meta.isAffix ? (state.dropdownList[1].affix = true) : (state.dropdownList[1].affix = false);
|
item.meta?.isAffix ? (state.dropdownList[1].affix = true) : (state.dropdownList[1].affix = false);
|
||||||
closeContextmenu();
|
closeContextmenu();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
state.isShow = true;
|
state.isShow = true;
|
||||||
@@ -84,14 +104,21 @@ export default defineComponent({
|
|||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
document.body.removeEventListener('click', closeContextmenu);
|
document.body.removeEventListener('click', closeContextmenu);
|
||||||
});
|
});
|
||||||
return {
|
// 监听下拉菜单位置
|
||||||
dropdowns,
|
watch(
|
||||||
openContextmenu,
|
() => props.dropdown,
|
||||||
closeContextmenu,
|
({ x }) => {
|
||||||
onCurrentContextmenuClick,
|
if (x + 117 > document.documentElement.clientWidth) state.arrowLeft = 117 - (document.documentElement.clientWidth - x);
|
||||||
...toRefs(state),
|
else state.arrowLeft = 10;
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 暴露变量
|
||||||
|
defineExpose({
|
||||||
|
openContextmenu,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -102,6 +129,7 @@ export default defineComponent({
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
.el-dropdown-menu__item {
|
.el-dropdown-menu__item {
|
||||||
font-size: 12px !important;
|
font-size: 12px !important;
|
||||||
|
white-space: nowrap;
|
||||||
i {
|
i {
|
||||||
font-size: 12px !important;
|
font-size: 12px !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
if (el) tagsRefs[k] = el;
|
if (el) tagsRefs[k] = el;
|
||||||
}
|
}
|
||||||
">
|
">
|
||||||
<i class="iconfont icon-webicon318 layout-navbars-tagsview-ul-li-iconfont font14"
|
<SvgIcon name="iconfont icon-tag-view-active" class="layout-navbars-tagsview-ul-li-iconfont font14"
|
||||||
v-if="isActive(v)"></i>
|
v-if="isActive(v)" />
|
||||||
<SvgIcon :name="v.meta.icon" class="layout-navbars-tagsview-ul-li-iconfont"
|
<SvgIcon :name="v.meta.icon" class="layout-navbars-tagsview-ul-li-iconfont"
|
||||||
v-if="!isActive(v) && themeConfig.isTagsviewIcon" />
|
v-if="!isActive(v) && themeConfig.isTagsviewIcon" />
|
||||||
<span>{{ v.meta.title }}</span>
|
<span>{{ v.meta.title }}</span>
|
||||||
@@ -523,4 +523,5 @@ onBeforeRouteUpdate((to) => {
|
|||||||
|
|
||||||
.layout-navbars-tagsview-shadow {
|
.layout-navbars-tagsview-shadow {
|
||||||
box-shadow: rgb(0 21 41 / 4%) 0px 1px 4px;
|
box-shadow: rgb(0 21 41 / 4%) 0px 1px 4px;
|
||||||
}</style>
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="instances-box layout-aside">
|
<div class="instances-box">
|
||||||
<el-row type="flex" justify="space-between">
|
<el-row type="flex" justify="space-between">
|
||||||
<el-col :span="24" class="el-scrollbar flex-auto" style="overflow: auto">
|
<el-col :span="24" class="el-scrollbar flex-auto" style="overflow: auto">
|
||||||
<el-input v-model="filterText" placeholder="输入关键字->搜索已展开节点信息" clearable size="small" class="mb5" />
|
<el-input v-model="filterText" placeholder="输入关键字->搜索已展开节点信息" clearable size="small" class="mb5" />
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
<el-tree ref="treeRef" :style="{ maxHeight: state.height, height: state.height, overflow: 'auto' }"
|
<el-tree ref="treeRef" :style="{ maxHeight: state.height, height: state.height, overflow: 'auto' }"
|
||||||
:highlight-current="true" :indent="7" :load="loadNode" :props="treeProps" lazy node-key="key"
|
:highlight-current="true" :indent="7" :load="loadNode" :props="treeProps" lazy node-key="key"
|
||||||
:expand-on-click-node="true" :filter-node-method="filterNode" @node-click="treeNodeClick"
|
:expand-on-click-node="true" :filter-node-method="filterNode" @node-click="treeNodeClick"
|
||||||
@node-expand="treeNodeClick">
|
@node-expand="treeNodeClick" @node-contextmenu="nodeContextmenu">
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span>
|
<span>
|
||||||
<span v-if="data.type == TagTreeNode.TagPath">
|
<span v-if="data.type == TagTreeNode.TagPath">
|
||||||
@@ -19,16 +19,13 @@
|
|||||||
<span class="ml3">
|
<span class="ml3">
|
||||||
<slot name="label" :data="data"> {{ data.label }}</slot>
|
<slot name="label" :data="data"> {{ data.label }}</slot>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="ml3">
|
|
||||||
<slot name="option" :data="data"></slot>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<contextmenu :dropdown="state.dropdown" :items="state.contextmenuItems" ref="contextmenuRef"
|
||||||
|
@currentContextmenuClick="onCurrentContextmenuClick" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -36,6 +33,7 @@
|
|||||||
import { onMounted, reactive, ref, watch, toRefs } from 'vue';
|
import { onMounted, reactive, ref, watch, toRefs } from 'vue';
|
||||||
import { TagTreeNode } from './tag';
|
import { TagTreeNode } from './tag';
|
||||||
import TagInfo from './TagInfo.vue';
|
import TagInfo from './TagInfo.vue';
|
||||||
|
import Contextmenu from '@/components/contextmenu/index.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
height: {
|
height: {
|
||||||
@@ -45,6 +43,10 @@ const props = defineProps({
|
|||||||
load: {
|
load: {
|
||||||
type: Function,
|
type: Function,
|
||||||
required: true,
|
required: true,
|
||||||
|
},
|
||||||
|
loadContextmenuItems: {
|
||||||
|
type: Function,
|
||||||
|
required: false,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -54,12 +56,18 @@ const treeProps = {
|
|||||||
isLeaf: 'isLeaf',
|
isLeaf: 'isLeaf',
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['nodeClick'])
|
const emit = defineEmits(['nodeClick', 'currentContextmenuClick'])
|
||||||
const treeRef: any = ref(null)
|
const treeRef: any = ref(null)
|
||||||
|
const contextmenuRef = ref();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
height: 600 as any,
|
height: 600 as any,
|
||||||
filterText: '',
|
filterText: '',
|
||||||
|
dropdown: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
contextmenuItems: [],
|
||||||
opend: {},
|
opend: {},
|
||||||
})
|
})
|
||||||
const { filterText } = toRefs(state)
|
const { filterText } = toRefs(state)
|
||||||
@@ -101,6 +109,29 @@ const loadNode = async (node: any, resolve: any) => {
|
|||||||
|
|
||||||
const treeNodeClick = (data: any) => {
|
const treeNodeClick = (data: any) => {
|
||||||
emit('nodeClick', data);
|
emit('nodeClick', data);
|
||||||
|
// 关闭可能存在的右击菜单
|
||||||
|
contextmenuRef.value.closeContextmenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 树节点右击事件
|
||||||
|
const nodeContextmenu = (event: any, data: any) => {
|
||||||
|
if (!props.loadContextmenuItems) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 加载当前节点是否需要显示右击菜单
|
||||||
|
const items = props.loadContextmenuItems(data)
|
||||||
|
if (!items || items.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.contextmenuItems = items;
|
||||||
|
const { clientX, clientY } = event;
|
||||||
|
state.dropdown.x = clientX;
|
||||||
|
state.dropdown.y = clientY;
|
||||||
|
contextmenuRef.value.openContextmenu(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCurrentContextmenuClick = (clickData: any) => {
|
||||||
|
emit('currentContextmenuClick', clickData);
|
||||||
}
|
}
|
||||||
|
|
||||||
const reloadNode = (nodeKey: any) => {
|
const reloadNode = (nodeKey: any) => {
|
||||||
@@ -125,6 +156,7 @@ defineExpose({
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.instances-box {
|
.instances-box {
|
||||||
overflow: 'auto';
|
overflow: 'auto';
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.el-tree {
|
.el-tree {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
@@ -23,13 +23,15 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
<el-row type="flex">
|
<el-row type="flex">
|
||||||
<el-col :span="4" style="border-left: 1px solid #eee; margin-top: 10px">
|
<el-col :span="4" style="border-left: 1px solid #eee; margin-top: 10px">
|
||||||
<tag-tree ref="tagTreeRef" @node-click="nodeClick" :load="loadNode" :height="state.tagTreeHeight">
|
<tag-tree ref="tagTreeRef" @node-click="nodeClick" :load="loadNode" :load-contextmenu-items="getContextmenuItems" @current-contextmenu-click="onCurrentContextmenuClick"
|
||||||
|
:height="state.tagTreeHeight">
|
||||||
<template #prefix="{ data }">
|
<template #prefix="{ data }">
|
||||||
<span v-if="data.type == NodeType.DbInst">
|
<span v-if="data.type == NodeType.DbInst">
|
||||||
<el-popover placement="right-start" title="数据库实例信息" trigger="hover" :width="210">
|
<el-popover placement="right-start" title="数据库实例信息" trigger="hover" :width="210">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<SvgIcon v-if="data.params.type === 'mysql'" name="iconfont icon-op-mysql" :size="18" />
|
<SvgIcon v-if="data.params.type === 'mysql'" name="iconfont icon-op-mysql" :size="18" />
|
||||||
<SvgIcon v-if="data.params.type === 'postgres'" name="iconfont icon-op-postgres" :size="18" />
|
<SvgIcon v-if="data.params.type === 'postgres'" name="iconfont icon-op-postgres"
|
||||||
|
:size="18" />
|
||||||
|
|
||||||
<SvgIcon name="InfoFilled" v-else />
|
<SvgIcon name="InfoFilled" v-else />
|
||||||
</template>
|
</template>
|
||||||
@@ -57,12 +59,8 @@
|
|||||||
<SvgIcon name="Calendar" color="#409eff" />
|
<SvgIcon name="Calendar" color="#409eff" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<SvgIcon name="Files" v-if="data.type == NodeType.SqlMenu || data.type == NodeType.Sql" color="#f56c6c" />
|
<SvgIcon name="Files" v-if="data.type == NodeType.SqlMenu || data.type == NodeType.Sql"
|
||||||
</template>
|
color="#f56c6c" />
|
||||||
<template #option="{data}">
|
|
||||||
<span v-if="data.type == NodeType.TableMenu">
|
|
||||||
<el-link @click="reloadTables(data.key)" icon="refresh" :underline="false"></el-link>
|
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
</tag-tree>
|
</tag-tree>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -119,6 +117,9 @@ class NodeType {
|
|||||||
static Table = 5;
|
static Table = 5;
|
||||||
static Sql = 6;
|
static Sql = 6;
|
||||||
}
|
}
|
||||||
|
class ContextmenuClickId {
|
||||||
|
static ReloadTable = 0
|
||||||
|
}
|
||||||
|
|
||||||
const tagTreeRef: any = ref(null)
|
const tagTreeRef: any = ref(null)
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ const state = reactive({
|
|||||||
tabs,
|
tabs,
|
||||||
dataTabsTableHeight: '600',
|
dataTabsTableHeight: '600',
|
||||||
editorHeight: '600',
|
editorHeight: '600',
|
||||||
tagTreeHeight: window.innerHeight - 178 + 'px',
|
tagTreeHeight: window.innerHeight - 173 + 'px',
|
||||||
genSqlDialog: {
|
genSqlDialog: {
|
||||||
visible: false,
|
visible: false,
|
||||||
sql: '',
|
sql: '',
|
||||||
@@ -171,9 +172,9 @@ const getInsts = async () => {
|
|||||||
if (!res.total) return
|
if (!res.total) return
|
||||||
for (const db of res.list) {
|
for (const db of res.list) {
|
||||||
const tagPath = db.tagPath;
|
const tagPath = db.tagPath;
|
||||||
let redisInsts = instMap.get(tagPath) || [];
|
let dbInsts = instMap.get(tagPath) || [];
|
||||||
redisInsts.push(db);
|
dbInsts.push(db);
|
||||||
instMap.set(tagPath, redisInsts);
|
instMap.set(tagPath, dbInsts?.sort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,6 +262,24 @@ const nodeClick = async (data: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getContextmenuItems = (data: any) => {
|
||||||
|
const dataType = data.type;
|
||||||
|
if (dataType === NodeType.TableMenu) {
|
||||||
|
return [
|
||||||
|
{ contextMenuClickId: ContextmenuClickId.ReloadTable, txt: '刷新', icon: 'RefreshRight' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前右击菜单点击事件
|
||||||
|
const onCurrentContextmenuClick = (clickData: any) => {
|
||||||
|
const clickId = clickData.id;
|
||||||
|
if (clickId == ContextmenuClickId.ReloadTable) {
|
||||||
|
reloadTables(clickData.item.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getTables = async (params: any) => {
|
const getTables = async (params: any) => {
|
||||||
const { id, db } = params;
|
const { id, db } = params;
|
||||||
let tables = await DbInst.getInst(id).loadTables(db, state.reloadStatus);
|
let tables = await DbInst.getInst(id).loadTables(db, state.reloadStatus);
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ export class DbInst {
|
|||||||
if (!reload && tables) {
|
if (!reload && tables) {
|
||||||
return tables;
|
return tables;
|
||||||
}
|
}
|
||||||
|
// 重置列信息缓存与表提示信息
|
||||||
|
db.columnsMap?.clear();
|
||||||
|
db.tableHints = null;
|
||||||
console.log(`load tables -> dbName: ${dbName}`);
|
console.log(`load tables -> dbName: ${dbName}`);
|
||||||
tables = await dbApi.tableMetadata.request({ id: this.id, db: dbName });
|
tables = await dbApi.tableMetadata.request({ id: this.id, db: dbName });
|
||||||
db.tables = tables;
|
db.tables = tables;
|
||||||
|
|||||||
Reference in New Issue
Block a user