mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-12-02 22:10:25 +08:00
refactor: 标签树展示调整
This commit is contained in:
@@ -45,7 +45,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
items: {
|
items: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
>
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span>
|
<span>
|
||||||
<span v-if="data.type == TagTreeNode.TagPath">
|
<span v-if="data.type.value == TagTreeNode.TagPath">
|
||||||
<tag-info :tag-path="data.label" />
|
<tag-info :tag-path="data.label" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -54,7 +54,11 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
load: {
|
load: {
|
||||||
type: Function,
|
type: Function,
|
||||||
required: true,
|
required: false,
|
||||||
|
},
|
||||||
|
loadTags: {
|
||||||
|
type: Function,
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
loadContextmenuItems: {
|
loadContextmenuItems: {
|
||||||
type: Function,
|
type: Function,
|
||||||
@@ -117,7 +121,13 @@ const loadNode = async (node: any, resolve: any) => {
|
|||||||
}
|
}
|
||||||
let nodes = [];
|
let nodes = [];
|
||||||
try {
|
try {
|
||||||
|
if (node.level == 0 && props.loadTags) {
|
||||||
|
nodes = await props.loadTags(node);
|
||||||
|
} else if (props.load) {
|
||||||
nodes = await props.load(node);
|
nodes = await props.load(node);
|
||||||
|
} else {
|
||||||
|
nodes = await node.data.loadChildren();
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
@@ -126,18 +136,23 @@ const loadNode = async (node: any, resolve: any) => {
|
|||||||
|
|
||||||
const treeNodeClick = (data: any) => {
|
const treeNodeClick = (data: any) => {
|
||||||
emit('nodeClick', data);
|
emit('nodeClick', data);
|
||||||
|
if (data.type.nodeClickFunc) {
|
||||||
|
data.type.nodeClickFunc(data);
|
||||||
|
}
|
||||||
// 关闭可能存在的右击菜单
|
// 关闭可能存在的右击菜单
|
||||||
contextmenuRef.value.closeContextmenu();
|
contextmenuRef.value.closeContextmenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 树节点右击事件
|
// 树节点右击事件
|
||||||
const nodeContextmenu = (event: any, data: any) => {
|
const nodeContextmenu = (event: any, data: any) => {
|
||||||
if (!props.loadContextmenuItems) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 加载当前节点是否需要显示右击菜单
|
// 加载当前节点是否需要显示右击菜单
|
||||||
const items = props.loadContextmenuItems(data);
|
let items = data.type.contextMenuItems;
|
||||||
if (!items || items.length == 0) {
|
if (!items || items.length == 0) {
|
||||||
|
if (props.loadContextmenuItems) {
|
||||||
|
items = props.loadContextmenuItems(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!items) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.contextmenuItems = items;
|
state.contextmenuItems = items;
|
||||||
|
|||||||
@@ -12,18 +12,24 @@ export class TagTreeNode {
|
|||||||
/**
|
/**
|
||||||
* 树节点类型
|
* 树节点类型
|
||||||
*/
|
*/
|
||||||
type: any;
|
type: NodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为叶子节点
|
||||||
|
*/
|
||||||
isLeaf: boolean = false;
|
isLeaf: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 额外需要传递的参数
|
||||||
|
*/
|
||||||
params: any;
|
params: any;
|
||||||
|
|
||||||
static TagPath = -1;
|
static TagPath = -1;
|
||||||
|
|
||||||
constructor(key: any, label: string, type?: any) {
|
constructor(key: any, label: string, type?: NodeType) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.type = type || TagTreeNode.TagPath;
|
this.type = type || new NodeType(TagTreeNode.TagPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
withIsLeaf(isLeaf: boolean) {
|
withIsLeaf(isLeaf: boolean) {
|
||||||
@@ -35,4 +41,68 @@ export class TagTreeNode {
|
|||||||
this.params = params;
|
this.params = params;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载子节点,使用节点类型的loadNodesFunc去加载子节点
|
||||||
|
* @returns 子节点信息
|
||||||
|
*/
|
||||||
|
async loadChildren() {
|
||||||
|
if (this.isLeaf) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (this.type && this.type.loadNodesFunc) {
|
||||||
|
return await this.type.loadNodesFunc(this);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点类型,用于加载子节点及点击事件等
|
||||||
|
*/
|
||||||
|
export class NodeType {
|
||||||
|
/**
|
||||||
|
* 节点类型值
|
||||||
|
*/
|
||||||
|
value: number;
|
||||||
|
|
||||||
|
contextMenuItems: [];
|
||||||
|
|
||||||
|
loadNodesFunc: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>;
|
||||||
|
|
||||||
|
nodeClickFunc: (node: TagTreeNode) => void;
|
||||||
|
|
||||||
|
constructor(value: number) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赋值加载子节点回调函数
|
||||||
|
* @param func 加载子节点回调函数
|
||||||
|
* @returns this
|
||||||
|
*/
|
||||||
|
withLoadNodesFunc(func: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>) {
|
||||||
|
this.loadNodesFunc = func;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赋值节点点击事件回调函数
|
||||||
|
* @param func 节点点击事件回调函数
|
||||||
|
* @returns this
|
||||||
|
*/
|
||||||
|
withNodeClickFunc(func: (node: TagTreeNode) => void) {
|
||||||
|
this.nodeClickFunc = func;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赋值右击菜单按钮选项
|
||||||
|
* @param contextMenuItems 右击菜单按钮选项
|
||||||
|
* @returns this
|
||||||
|
*/
|
||||||
|
withContextMenuItems(contextMenuItems: []) {
|
||||||
|
this.contextMenuItems = contextMenuItems;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,16 +31,9 @@
|
|||||||
|
|
||||||
<el-row type="flex">
|
<el-row type="flex">
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<tag-tree
|
<tag-tree ref="tagTreeRef" :loadTags="loadTags" @current-contextmenu-click="onCurrentContextmenuClick" :height="state.tagTreeHeight">
|
||||||
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.value == SqlExecNodeType.DbInst">
|
||||||
<el-popover :show-after="500" placement="right-start" title="数据库实例信息" trigger="hover" :width="210">
|
<el-popover :show-after="500" 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" />
|
||||||
@@ -60,13 +53,13 @@
|
|||||||
</el-popover>
|
</el-popover>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<SvgIcon v-if="data.type == NodeType.Db" name="Coin" color="#67c23a" />
|
<SvgIcon v-if="data.type.value == SqlExecNodeType.Db" name="Coin" color="#67c23a" />
|
||||||
|
|
||||||
<SvgIcon name="Calendar" v-if="data.type == NodeType.TableMenu" color="#409eff" />
|
<SvgIcon name="Calendar" v-if="data.type.value == SqlExecNodeType.TableMenu" color="#409eff" />
|
||||||
|
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
:show-after="500"
|
:show-after="500"
|
||||||
v-if="data.type == NodeType.Table"
|
v-if="data.type.value == SqlExecNodeType.Table"
|
||||||
effect="customized"
|
effect="customized"
|
||||||
:content="data.params.tableComment"
|
:content="data.params.tableComment"
|
||||||
placement="top-end"
|
placement="top-end"
|
||||||
@@ -74,11 +67,14 @@
|
|||||||
<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.value == SqlExecNodeType.SqlMenu || data.type.value == SqlExecNodeType.Sql" color="#f56c6c" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #suffix="{ data }">
|
<template #suffix="{ data }">
|
||||||
<span class="db-table-size" v-if="data.type == NodeType.Table">{{ ` ${data.params.size}` }}</span>
|
<span class="db-table-size" v-if="data.type.value == SqlExecNodeType.Table && data.params.size">{{ ` ${data.params.size}` }}</span>
|
||||||
|
<span class="db-table-size" v-if="data.type.value == SqlExecNodeType.TableMenu && data.params.dbTableSize">{{
|
||||||
|
` ${data.params.dbTableSize}`
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</tag-tree>
|
</tag-tree>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -119,7 +115,7 @@ import { defineAsyncComponent, onMounted, reactive, ref, toRefs, onBeforeUnmount
|
|||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { formatByteSize } from '@/common/utils/format';
|
import { formatByteSize } from '@/common/utils/format';
|
||||||
import { DbInst, TabInfo, TabType, registerDbCompletionItemProvider } from './db';
|
import { DbInst, TabInfo, TabType, registerDbCompletionItemProvider } from './db';
|
||||||
import { TagTreeNode } from '../component/tag';
|
import { TagTreeNode, NodeType } from '../component/tag';
|
||||||
import TagTree from '../component/TagTree.vue';
|
import TagTree from '../component/TagTree.vue';
|
||||||
import { dbApi } from './api';
|
import { dbApi } from './api';
|
||||||
import { dispposeCompletionItemProvider } from '../../../components/monaco/completionItemProvider';
|
import { dispposeCompletionItemProvider } from '../../../components/monaco/completionItemProvider';
|
||||||
@@ -129,7 +125,7 @@ const TableData = defineAsyncComponent(() => import('./component/tab/TableData.v
|
|||||||
/**
|
/**
|
||||||
* 树节点类型
|
* 树节点类型
|
||||||
*/
|
*/
|
||||||
class NodeType {
|
class SqlExecNodeType {
|
||||||
static DbInst = 1;
|
static DbInst = 1;
|
||||||
static Db = 2;
|
static Db = 2;
|
||||||
static TableMenu = 3;
|
static TableMenu = 3;
|
||||||
@@ -137,10 +133,115 @@ class NodeType {
|
|||||||
static Table = 5;
|
static Table = 5;
|
||||||
static Sql = 6;
|
static Sql = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContextmenuClickId {
|
class ContextmenuClickId {
|
||||||
static ReloadTable = 0;
|
static ReloadTable = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// node节点点击时,触发改变db事件
|
||||||
|
const changeDb = (nodeData: TagTreeNode) => {
|
||||||
|
const params = nodeData.params;
|
||||||
|
changeSchema({ id: params.id, name: params.name, type: params.type, tagPath: params.tagPath, databases: params.database }, params.db);
|
||||||
|
};
|
||||||
|
|
||||||
|
// tagpath 节点类型
|
||||||
|
const NodeTypeTagPath = new NodeType(TagTreeNode.TagPath).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const dbInfos = instMap.get(parentNode.key);
|
||||||
|
if (!dbInfos) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return dbInfos?.map((x: any) => {
|
||||||
|
return new TagTreeNode(`${parentNode.key}.${x.id}`, x.name, NodeTypeDbInst).withParams(x);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 数据库实例节点类型
|
||||||
|
const NodeTypeDbInst = new NodeType(SqlExecNodeType.DbInst)
|
||||||
|
.withLoadNodesFunc((parentNode: TagTreeNode) => {
|
||||||
|
const params = parentNode.params;
|
||||||
|
const dbs = params.database.split(' ')?.sort();
|
||||||
|
return dbs.map((x: any) => {
|
||||||
|
return new TagTreeNode(`${parentNode.key}.${x}`, x, NodeTypeDb).withParams({
|
||||||
|
tagPath: params.tagPath,
|
||||||
|
id: params.id,
|
||||||
|
name: params.name,
|
||||||
|
type: params.type,
|
||||||
|
dbs: dbs,
|
||||||
|
db: x,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.withNodeClickFunc(changeDb);
|
||||||
|
|
||||||
|
// 数据库节点
|
||||||
|
const NodeTypeDb = new NodeType(SqlExecNodeType.Db)
|
||||||
|
.withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const params = parentNode.params;
|
||||||
|
return [
|
||||||
|
new TagTreeNode(`${params.id}.${params.db}.table-menu`, '表', NodeTypeTableMenu).withParams(params),
|
||||||
|
new TagTreeNode(getSqlMenuNodeKey(params.id, params.db), 'SQL', NodeTypeSqlMenu).withParams(params),
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.withNodeClickFunc(changeDb);
|
||||||
|
|
||||||
|
// 数据库表菜单节点
|
||||||
|
const NodeTypeTableMenu = new NodeType(SqlExecNodeType.TableMenu)
|
||||||
|
.withContextMenuItems([{ contextMenuClickId: ContextmenuClickId.ReloadTable, txt: '刷新', icon: 'RefreshRight' }] as any)
|
||||||
|
.withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const params = parentNode.params;
|
||||||
|
const { id, db } = params;
|
||||||
|
// 获取当前库的所有表信息
|
||||||
|
let tables = await DbInst.getInst(id).loadTables(db, state.reloadStatus);
|
||||||
|
state.reloadStatus = false;
|
||||||
|
let dbTableSize = 0;
|
||||||
|
const tablesNode = tables.map((x: any) => {
|
||||||
|
dbTableSize += x.dataLength + x.indexLength;
|
||||||
|
return new TagTreeNode(`${id}.${db}.${x.tableName}`, x.tableName, NodeTypeTable).withIsLeaf(true).withParams({
|
||||||
|
id,
|
||||||
|
db,
|
||||||
|
tableName: x.tableName,
|
||||||
|
tableComment: x.tableComment,
|
||||||
|
size: formatByteSize(x.dataLength + x.indexLength, 1),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 设置父节点参数的表大小
|
||||||
|
parentNode.params.dbTableSize = formatByteSize(dbTableSize);
|
||||||
|
return tablesNode;
|
||||||
|
})
|
||||||
|
.withNodeClickFunc(changeDb);
|
||||||
|
|
||||||
|
// 数据库sql模板菜单节点
|
||||||
|
const NodeTypeSqlMenu = new NodeType(SqlExecNodeType.SqlMenu)
|
||||||
|
.withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const params = parentNode.params;
|
||||||
|
const id = params.id;
|
||||||
|
const db = params.db;
|
||||||
|
const dbs = params.dbs;
|
||||||
|
// 加载用户保存的sql脚本
|
||||||
|
const sqls = await dbApi.getSqlNames.request({ id: id, db: db });
|
||||||
|
return sqls.map((x: any) => {
|
||||||
|
return new TagTreeNode(`${id}.${db}.${x.name}`, x.name, NodeTypeSql).withIsLeaf(true).withParams({
|
||||||
|
id,
|
||||||
|
db,
|
||||||
|
dbs,
|
||||||
|
sqlName: x.name,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.withNodeClickFunc(changeDb);
|
||||||
|
|
||||||
|
// 表节点类型
|
||||||
|
const NodeTypeTable = new NodeType(SqlExecNodeType.Table).withNodeClickFunc((nodeData: TagTreeNode) => {
|
||||||
|
const params = nodeData.params;
|
||||||
|
loadTableData({ id: params.id, nodeKey: nodeData.key }, params.db, params.tableName);
|
||||||
|
});
|
||||||
|
|
||||||
|
// sql模板节点类型
|
||||||
|
const NodeTypeSql = new NodeType(SqlExecNodeType.Sql).withNodeClickFunc((nodeData: TagTreeNode) => {
|
||||||
|
const params = nodeData.params;
|
||||||
|
addQueryTab({ id: params.id, nodeKey: nodeData.key, dbs: params.dbs }, params.db, params.sqlName);
|
||||||
|
});
|
||||||
|
|
||||||
const tagTreeRef: any = ref(null);
|
const tagTreeRef: any = ref(null);
|
||||||
|
|
||||||
const tabs: Map<string, TabInfo> = new Map();
|
const tabs: Map<string, TabInfo> = new Map();
|
||||||
@@ -200,97 +301,16 @@ const getInsts = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载树节点
|
* 加载标签树节点
|
||||||
* @param {Object} node
|
|
||||||
* @param {Object} resolve
|
|
||||||
*/
|
*/
|
||||||
const loadNode = async (node: any) => {
|
const loadTags = async () => {
|
||||||
// 一级为tagPath
|
|
||||||
if (node.level === 0) {
|
|
||||||
await getInsts();
|
await getInsts();
|
||||||
const tagPaths = instMap.keys();
|
const tagPaths = instMap.keys();
|
||||||
const tagNodes = [];
|
const tagNodes = [];
|
||||||
for (let tagPath of tagPaths) {
|
for (let tagPath of tagPaths) {
|
||||||
tagNodes.push(new TagTreeNode(tagPath, tagPath));
|
tagNodes.push(new TagTreeNode(tagPath, tagPath, NodeTypeTagPath));
|
||||||
}
|
}
|
||||||
return tagNodes;
|
return tagNodes;
|
||||||
}
|
|
||||||
|
|
||||||
const data = node.data;
|
|
||||||
const nodeType = data.type;
|
|
||||||
const params = data.params;
|
|
||||||
|
|
||||||
// 点击tagPath -> 加载数据库实例信息列表
|
|
||||||
if (nodeType === TagTreeNode.TagPath) {
|
|
||||||
const dbInfos = instMap.get(data.key);
|
|
||||||
return dbInfos?.map((x: any) => {
|
|
||||||
return new TagTreeNode(`${data.key}.${x.id}`, x.name, NodeType.DbInst).withParams(x);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击数据库实例 -> 加载库列表
|
|
||||||
if (nodeType === NodeType.DbInst) {
|
|
||||||
const dbs = params.database.split(' ')?.sort();
|
|
||||||
return dbs.map((x: any) => {
|
|
||||||
return new TagTreeNode(`${data.key}.${x}`, x, NodeType.Db).withParams({
|
|
||||||
tagPath: params.tagPath,
|
|
||||||
id: params.id,
|
|
||||||
name: params.name,
|
|
||||||
type: params.type,
|
|
||||||
dbs: dbs,
|
|
||||||
db: x,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击数据库 -> 加载 表&Sql 菜单
|
|
||||||
if (nodeType === NodeType.Db) {
|
|
||||||
return [
|
|
||||||
new TagTreeNode(`${params.id}.${params.db}.table-menu`, '表', NodeType.TableMenu).withParams(params),
|
|
||||||
new TagTreeNode(getSqlMenuNodeKey(params.id, params.db), 'SQL', NodeType.SqlMenu).withParams(params),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击表菜单 -> 加载表列表
|
|
||||||
if (nodeType === NodeType.TableMenu) {
|
|
||||||
return await getTables(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodeType === NodeType.SqlMenu) {
|
|
||||||
return await loadSqls(params.id, params.db, params.dbs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const nodeClick = async (data: any) => {
|
|
||||||
const params = data.params;
|
|
||||||
const nodeKey = data.key;
|
|
||||||
const dataType = data.type;
|
|
||||||
// 点击数据库,修改当前数据库信息
|
|
||||||
if (dataType === NodeType.Db || dataType === NodeType.SqlMenu || dataType === NodeType.TableMenu || dataType === NodeType.DbInst) {
|
|
||||||
changeSchema({ id: params.id, name: params.name, type: params.type, tagPath: params.tagPath, databases: params.database }, params.db);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击表加载表数据tab
|
|
||||||
if (dataType === NodeType.Table) {
|
|
||||||
await loadTableData({ id: params.id, nodeKey: nodeKey }, params.db, params.tableName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击表加载表数据tab
|
|
||||||
if (dataType === NodeType.Sql) {
|
|
||||||
await addQueryTab({ id: params.id, nodeKey: nodeKey, dbs: params.dbs }, params.db, params.sqlName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getContextmenuItems = (data: any) => {
|
|
||||||
const dataType = data.type;
|
|
||||||
if (dataType === NodeType.TableMenu) {
|
|
||||||
return [{ contextMenuClickId: ContextmenuClickId.ReloadTable, txt: '刷新', icon: 'RefreshRight' }];
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 当前右击菜单点击事件
|
// 当前右击菜单点击事件
|
||||||
@@ -301,39 +321,6 @@ const onCurrentContextmenuClick = (clickData: any) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTables = async (params: any) => {
|
|
||||||
const { id, db } = params;
|
|
||||||
let tables = await DbInst.getInst(id).loadTables(db, state.reloadStatus);
|
|
||||||
state.reloadStatus = false;
|
|
||||||
return tables.map((x: any) => {
|
|
||||||
return new TagTreeNode(`${id}.${db}.${x.tableName}`, x.tableName, NodeType.Table).withIsLeaf(true).withParams({
|
|
||||||
id,
|
|
||||||
db,
|
|
||||||
tableName: x.tableName,
|
|
||||||
tableComment: x.tableComment,
|
|
||||||
size: formatByteSize(x.dataLength + x.indexLength, 1),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载用户保存的sql脚本
|
|
||||||
*
|
|
||||||
* @param inst
|
|
||||||
* @param schema
|
|
||||||
*/
|
|
||||||
const loadSqls = async (id: any, db: string, dbs: any) => {
|
|
||||||
const sqls = await dbApi.getSqlNames.request({ id: id, db: db });
|
|
||||||
return sqls.map((x: any) => {
|
|
||||||
return new TagTreeNode(`${id}.${db}.${x.name}`, x.name, NodeType.Sql).withIsLeaf(true).withParams({
|
|
||||||
id,
|
|
||||||
db,
|
|
||||||
dbs,
|
|
||||||
sqlName: x.name,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 选择数据库
|
// 选择数据库
|
||||||
const changeSchema = (inst: any, schema: string) => {
|
const changeSchema = (inst: any, schema: string) => {
|
||||||
state.nowDbInst = DbInst.getOrNewInst(inst);
|
state.nowDbInst = DbInst.getOrNewInst(inst);
|
||||||
@@ -372,6 +359,7 @@ const addQueryTab = async (inst: any, db: string, sqlName: string = '') => {
|
|||||||
ElMessage.warning('请选择数据库实例及对应的schema');
|
ElMessage.warning('请选择数据库实例及对应的schema');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
changeSchema(inst, db);
|
||||||
|
|
||||||
const dbId = inst.id;
|
const dbId = inst.id;
|
||||||
let label;
|
let label;
|
||||||
@@ -470,31 +458,9 @@ const reloadTables = (nodeKey: string) => {
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.db-sql-exec {
|
.db-sql-exec {
|
||||||
.sql-file-exec {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
position: relative;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.db-table-size {
|
.db-table-size {
|
||||||
color: #c4c9c4;
|
color: #c4c9c4;
|
||||||
font-size: 10px;
|
font-size: 9px;
|
||||||
}
|
|
||||||
|
|
||||||
.sqlEditor {
|
|
||||||
font-size: 8pt;
|
|
||||||
font-weight: 600;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-move-resize {
|
|
||||||
cursor: n-resize;
|
|
||||||
height: 3px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#data-exec {
|
#data-exec {
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<div>
|
<div>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<tag-tree @node-click="nodeClick" :load="loadNode">
|
<tag-tree :loadTags="loadTags">
|
||||||
<template #prefix="{ data }">
|
<template #prefix="{ data }">
|
||||||
<span v-if="data.type == NodeType.Mongo">
|
<span v-if="data.type.value == MongoNodeType.Mongo">
|
||||||
<el-popover :show-after="500" placement="right-start" title="mongo实例信息" trigger="hover" :width="210">
|
<el-popover :show-after="500" placement="right-start" title="mongo实例信息" trigger="hover" :width="210">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<SvgIcon name="iconfont icon-op-mongo" :size="18" />
|
<SvgIcon name="iconfont icon-op-mongo" :size="18" />
|
||||||
@@ -18,14 +18,18 @@
|
|||||||
</el-popover>
|
</el-popover>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<SvgIcon v-if="data.type == NodeType.Dbs" name="Coin" color="#67c23a" />
|
<SvgIcon v-if="data.type.value == MongoNodeType.Dbs" name="Coin" color="#67c23a" />
|
||||||
|
|
||||||
<SvgIcon v-if="data.type == NodeType.Coll || data.type == NodeType.CollMenu" name="Document" class="color-primary" />
|
<SvgIcon
|
||||||
|
v-if="data.type.value == MongoNodeType.Coll || data.type.value == MongoNodeType.CollMenu"
|
||||||
|
name="Document"
|
||||||
|
class="color-primary"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #label="{ data }">
|
<template #label="{ data }">
|
||||||
<span v-if="data.type == NodeType.Dbs">
|
<span v-if="data.type.value == MongoNodeType.Dbs">
|
||||||
{{ data.params.dbName }}
|
{{ data.params.database }}
|
||||||
<span style="color: #8492a6; font-size: 13px"> [{{ formatByteSize(data.params.size) }}] </span>
|
<span style="color: #8492a6; font-size: 13px"> [{{ formatByteSize(data.params.size) }}] </span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -161,7 +165,7 @@ import { computed, defineAsyncComponent, reactive, ref, toRefs } from 'vue';
|
|||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
import { isTrue, notBlank } from '@/common/assert';
|
import { isTrue, notBlank } from '@/common/assert';
|
||||||
import { TagTreeNode } from '../component/tag';
|
import { TagTreeNode, NodeType } from '../component/tag';
|
||||||
import TagTree from '../component/TagTree.vue';
|
import TagTree from '../component/TagTree.vue';
|
||||||
import { formatByteSize } from '@/common/utils/format';
|
import { formatByteSize } from '@/common/utils/format';
|
||||||
|
|
||||||
@@ -175,13 +179,63 @@ const perms = {
|
|||||||
/**
|
/**
|
||||||
* 树节点类型
|
* 树节点类型
|
||||||
*/
|
*/
|
||||||
class NodeType {
|
class MongoNodeType {
|
||||||
static Mongo = 1;
|
static Mongo = 1;
|
||||||
static Dbs = 2;
|
static Dbs = 2;
|
||||||
static CollMenu = 3;
|
static CollMenu = 3;
|
||||||
static Coll = 4;
|
static Coll = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tagpath 节点类型
|
||||||
|
const NodeTypeTagPath = new NodeType(TagTreeNode.TagPath).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
// 点击标签 -> 显示mongo信息列表
|
||||||
|
const mongoInfos = instMap.get(parentNode.key);
|
||||||
|
if (!mongoInfos) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return mongoInfos?.map((x: any) => {
|
||||||
|
return new TagTreeNode(`${parentNode.key}.${x.id}`, x.name, NodeTypeMongo).withParams(x);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const NodeTypeMongo = new NodeType(MongoNodeType.Mongo).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const inst = parentNode.params;
|
||||||
|
// 点击mongo -> 加载mongo数据库列表
|
||||||
|
const res = await mongoApi.databases.request({ id: inst.id });
|
||||||
|
return res.Databases.map((x: any) => {
|
||||||
|
const database = x.Name;
|
||||||
|
return new TagTreeNode(`${inst.id}.${database}`, database, NodeTypeDbs).withParams({
|
||||||
|
id: inst.id,
|
||||||
|
database,
|
||||||
|
size: x.SizeOnDisk,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const NodeTypeDbs = new NodeType(MongoNodeType.Dbs).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const params = parentNode.params;
|
||||||
|
// 点击数据库列表 -> 加载数据库下拥有的菜单列表
|
||||||
|
return [new TagTreeNode(`${params.id}.${params.database}.mongo-coll`, '集合', NodeTypeCollMenu).withParams(params)];
|
||||||
|
});
|
||||||
|
|
||||||
|
const NodeTypeCollMenu = new NodeType(MongoNodeType.CollMenu).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const { id, database } = parentNode.params;
|
||||||
|
// 点击数据库集合节点 -> 加载集合列表
|
||||||
|
const colls = await mongoApi.collections.request({ id, database });
|
||||||
|
return colls.map((x: any) => {
|
||||||
|
return new TagTreeNode(`${id}.${database}.${x}`, x, NodeTypeColl).withIsLeaf(true).withParams({
|
||||||
|
id,
|
||||||
|
database,
|
||||||
|
collection: x,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const NodeTypeColl = new NodeType(MongoNodeType.Coll).withNodeClickFunc((nodeData: TagTreeNode) => {
|
||||||
|
const { id, database, collection } = nodeData.params;
|
||||||
|
changeCollection(id, database, collection);
|
||||||
|
});
|
||||||
|
|
||||||
const findParamInputRef: any = ref(null);
|
const findParamInputRef: any = ref(null);
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tags: [],
|
tags: [],
|
||||||
@@ -237,89 +291,16 @@ const getInsts = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载文件树节点
|
* 加载标签树树节点
|
||||||
* @param {Object} node
|
|
||||||
* @param {Object} resolve
|
|
||||||
*/
|
*/
|
||||||
const loadNode = async (node: any) => {
|
const loadTags = async () => {
|
||||||
// 一级为tagPath
|
|
||||||
if (node.level === 0) {
|
|
||||||
await getInsts();
|
await getInsts();
|
||||||
const tagPaths = instMap.keys();
|
const tagPaths = instMap.keys();
|
||||||
const tagNodes = [];
|
const tagNodes = [];
|
||||||
for (let tagPath of tagPaths) {
|
for (let tagPath of tagPaths) {
|
||||||
tagNodes.push(new TagTreeNode(tagPath, tagPath));
|
tagNodes.push(new TagTreeNode(tagPath, tagPath, NodeTypeTagPath));
|
||||||
}
|
}
|
||||||
return tagNodes;
|
return tagNodes;
|
||||||
}
|
|
||||||
|
|
||||||
const data = node.data;
|
|
||||||
const params = data.params;
|
|
||||||
const nodeType = data.type;
|
|
||||||
|
|
||||||
// 点击标签 -> 显示mongo信息列表
|
|
||||||
if (nodeType === TagTreeNode.TagPath) {
|
|
||||||
const mongoInfos = instMap.get(data.key);
|
|
||||||
return mongoInfos?.map((x: any) => {
|
|
||||||
return new TagTreeNode(`${data.key}.${x.id}`, x.name, NodeType.Mongo).withParams(x);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击mongo -> 加载mongo数据库列表
|
|
||||||
if (nodeType === NodeType.Mongo) {
|
|
||||||
return await getDatabases(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击数据库列表 -> 加载数据库下拥有的菜单列表
|
|
||||||
if (nodeType === NodeType.Dbs) {
|
|
||||||
return [new TagTreeNode(`${params.id}.${params.dbName}.mongo-coll`, '集合', NodeType.CollMenu).withParams(params)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击数据库集合节点 -> 加载集合列表
|
|
||||||
if (nodeType === NodeType.CollMenu) {
|
|
||||||
return await getCollections(params.id, params.dbName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取实例的所有库信息
|
|
||||||
* @param inst 实例信息
|
|
||||||
*/
|
|
||||||
const getDatabases = async (inst: any) => {
|
|
||||||
const res = await mongoApi.databases.request({ id: inst.id });
|
|
||||||
return res.Databases.map((x: any) => {
|
|
||||||
const dbName = x.Name;
|
|
||||||
return new TagTreeNode(`${inst.id}.${dbName}`, dbName, NodeType.Dbs).withParams({
|
|
||||||
id: inst.id,
|
|
||||||
dbName,
|
|
||||||
size: x.SizeOnDisk,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取集合列表信息
|
|
||||||
* @param inst
|
|
||||||
*/
|
|
||||||
const getCollections = async (id: any, database: string) => {
|
|
||||||
const colls = await mongoApi.collections.request({ id, database });
|
|
||||||
return colls.map((x: any) => {
|
|
||||||
return new TagTreeNode(`${id}.${database}.${x}`, x, NodeType.Coll).withIsLeaf(true).withParams({
|
|
||||||
id,
|
|
||||||
database,
|
|
||||||
collection: x,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const nodeClick = async (data: any) => {
|
|
||||||
// 点击集合
|
|
||||||
if (data.type === NodeType.Coll) {
|
|
||||||
const { id, database, collection } = data.params;
|
|
||||||
await changeCollection(id, database, collection);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeCollection = async (id: any, schema: string, collection: string) => {
|
const changeCollection = async (id: any, schema: string, collection: string) => {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<el-row type="flex" justify="space-between">
|
<el-row type="flex" justify="space-between">
|
||||||
<el-col :span="24" class="flex-auto">
|
<el-col :span="24" class="flex-auto">
|
||||||
<tag-tree @node-click="nodeClick" :load="loadNode">
|
<tag-tree :loadTags="loadTags">
|
||||||
<template #prefix="{ data }">
|
<template #prefix="{ data }">
|
||||||
<span v-if="data.type == NodeType.Redis">
|
<span v-if="data.type.value == RedisNodeType.Redis">
|
||||||
<el-popover :show-after="500" placement="right-start" title="redis实例信息" trigger="hover" :width="210">
|
<el-popover :show-after="500" placement="right-start" title="redis实例信息" trigger="hover" :width="210">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<SvgIcon name="iconfont icon-op-redis" :size="18" />
|
<SvgIcon name="iconfont icon-op-redis" :size="18" />
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
</el-popover>
|
</el-popover>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<SvgIcon v-if="data.type == NodeType.Db" name="Coin" color="#67c23a" />
|
<SvgIcon v-if="data.type.value == RedisNodeType.Db" name="Coin" color="#67c23a" />
|
||||||
</template>
|
</template>
|
||||||
</tag-tree>
|
</tag-tree>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -184,7 +184,7 @@ import { redisApi } from './api';
|
|||||||
import { ref, defineAsyncComponent, toRefs, reactive, onMounted, nextTick } from 'vue';
|
import { ref, defineAsyncComponent, toRefs, reactive, onMounted, nextTick } from 'vue';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { isTrue, notBlank, notNull } from '@/common/assert';
|
import { isTrue, notBlank, notNull } from '@/common/assert';
|
||||||
import { TagTreeNode } from '../component/tag';
|
import { TagTreeNode, NodeType } from '../component/tag';
|
||||||
import TagTree from '../component/TagTree.vue';
|
import TagTree from '../component/TagTree.vue';
|
||||||
import { keysToTree, sortByTreeNodes, keysToList } from './utils';
|
import { keysToTree, sortByTreeNodes, keysToList } from './utils';
|
||||||
|
|
||||||
@@ -193,11 +193,61 @@ const KeyDetail = defineAsyncComponent(() => import('./KeyDetail.vue'));
|
|||||||
/**
|
/**
|
||||||
* 树节点类型
|
* 树节点类型
|
||||||
*/
|
*/
|
||||||
class NodeType {
|
class RedisNodeType {
|
||||||
static Redis = 1;
|
static Redis = 1;
|
||||||
static Db = 2;
|
static Db = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tagpath 节点类型
|
||||||
|
const NodeTypeTagPath = new NodeType(TagTreeNode.TagPath).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const redisInfos = instMap.get(parentNode.key);
|
||||||
|
if (!redisInfos) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return redisInfos.map((x: any) => {
|
||||||
|
return new TagTreeNode(`${parentNode.key}.${x.id}`, x.name, NodeTypeRedis).withParams(x);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// redis实例节点类型
|
||||||
|
const NodeTypeRedis = new NodeType(RedisNodeType.Redis).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
|
||||||
|
const redisInfo = parentNode.params;
|
||||||
|
let dbs: TagTreeNode[] = redisInfo.db.split(',').map((x: string) => {
|
||||||
|
return new TagTreeNode(x, `db${x}`, NodeTypeDb).withIsLeaf(true).withParams({
|
||||||
|
id: redisInfo.id,
|
||||||
|
db: x,
|
||||||
|
name: `db${x}`,
|
||||||
|
keys: 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (redisInfo.mode == 'cluster') {
|
||||||
|
return dbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await redisApi.redisInfo.request({ id: redisInfo.id, host: redisInfo.host, section: 'Keyspace' });
|
||||||
|
for (let db in res.Keyspace) {
|
||||||
|
for (let d of dbs) {
|
||||||
|
if (db == d.params.name) {
|
||||||
|
d.params.keys = res.Keyspace[db]?.split(',')[0]?.split('=')[1] || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 替换label
|
||||||
|
dbs.forEach((e: any) => {
|
||||||
|
e.label = `${e.params.name} [${e.params.keys}]`;
|
||||||
|
});
|
||||||
|
return dbs;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 库节点类型
|
||||||
|
const NodeTypeDb = new NodeType(RedisNodeType.Db).withNodeClickFunc((nodeData: TagTreeNode) => {
|
||||||
|
resetScanParam();
|
||||||
|
state.scanParam.id = nodeData.params.id;
|
||||||
|
state.scanParam.db = nodeData.params.db;
|
||||||
|
scan();
|
||||||
|
});
|
||||||
|
|
||||||
const treeProps = {
|
const treeProps = {
|
||||||
label: 'name',
|
label: 'name',
|
||||||
children: 'children',
|
children: 'children',
|
||||||
@@ -270,80 +320,16 @@ const getInsts = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载文件树节点
|
* 加载标签树节点
|
||||||
* @param {Object} node
|
|
||||||
* @param {Object} resolve
|
|
||||||
*/
|
*/
|
||||||
const loadNode = async (node: any) => {
|
const loadTags = async () => {
|
||||||
// 一级为tagPath
|
|
||||||
if (node.level === 0) {
|
|
||||||
await getInsts();
|
await getInsts();
|
||||||
const tagPaths = instMap.keys();
|
const tagPaths = instMap.keys();
|
||||||
const tagNodes = [];
|
const tagNodes = [];
|
||||||
for (let tagPath of tagPaths) {
|
for (let tagPath of tagPaths) {
|
||||||
tagNodes.push(new TagTreeNode(tagPath, tagPath));
|
tagNodes.push(new TagTreeNode(tagPath, tagPath, NodeTypeTagPath));
|
||||||
}
|
}
|
||||||
return tagNodes;
|
return tagNodes;
|
||||||
}
|
|
||||||
|
|
||||||
const data = node.data;
|
|
||||||
// 点击tagPath -> 加载数据库信息列表
|
|
||||||
if (data.type === TagTreeNode.TagPath) {
|
|
||||||
const redisInfos = instMap.get(data.key);
|
|
||||||
return redisInfos?.map((x: any) => {
|
|
||||||
return new TagTreeNode(`${data.key}.${x.id}`, x.name, NodeType.Redis).withParams(x);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击redis实例 -> 加载库列表
|
|
||||||
if (data.type === NodeType.Redis) {
|
|
||||||
return await getDbs(data.params);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const nodeClick = (data: any) => {
|
|
||||||
// 点击库事件
|
|
||||||
if (data.type === NodeType.Db) {
|
|
||||||
resetScanParam();
|
|
||||||
state.scanParam.id = data.params.id;
|
|
||||||
state.scanParam.db = data.params.db;
|
|
||||||
scan();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有库信息
|
|
||||||
* @param redisInfo redis信息
|
|
||||||
*/
|
|
||||||
const getDbs = async (redisInfo: any) => {
|
|
||||||
let dbs: TagTreeNode[] = redisInfo.db.split(',').map((x: string) => {
|
|
||||||
return new TagTreeNode(x, `db${x}`, NodeType.Db).withIsLeaf(true).withParams({
|
|
||||||
id: redisInfo.id,
|
|
||||||
db: x,
|
|
||||||
name: `db${x}`,
|
|
||||||
keys: 0,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (redisInfo.mode == 'cluster') {
|
|
||||||
return dbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await redisApi.redisInfo.request({ id: redisInfo.id, host: redisInfo.host, section: 'Keyspace' });
|
|
||||||
for (let db in res.Keyspace) {
|
|
||||||
for (let d of dbs) {
|
|
||||||
if (db == d.params.name) {
|
|
||||||
d.params.keys = res.Keyspace[db]?.split(',')[0]?.split('=')[1] || 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 替换label
|
|
||||||
dbs.forEach((e: any) => {
|
|
||||||
e.label = `${e.params.name} [${e.params.keys}]`;
|
|
||||||
});
|
|
||||||
return dbs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const scan = async (appendKey = false) => {
|
const scan = async (appendKey = false) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user