db模块引入虚拟滚动树组件,改善大数据量下的性能问题

一些细节优化
This commit is contained in:
diant
2023-06-07 14:49:41 +08:00
parent cd9a87b7df
commit 9e68547cfb
12 changed files with 7568 additions and 4990 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon-db.png"><title>数据库文档管理</title><link href="css/chunk-vendors.2fa4c9b3.css" rel="preload" as="style"><link href="css/index.25fc971a.css" rel="preload" as="style"><link href="js/chunk-vendors.6270548d.js" rel="preload" as="script"><link href="js/index.c186cdcd.js" rel="preload" as="script"><link href="css/chunk-vendors.2fa4c9b3.css" rel="stylesheet"><link href="css/index.25fc971a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but zyplayer-db-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.6270548d.js"></script><script src="js/index.c186cdcd.js"></script></body></html> <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon-db.png"><title>数据库文档管理</title><link href="css/chunk-vendors.be60d3b3.css" rel="preload" as="style"><link href="css/index.438e06ca.css" rel="preload" as="style"><link href="js/chunk-vendors.ce4976ca.js" rel="preload" as="script"><link href="js/index.2e4681ba.js" rel="preload" as="script"><link href="css/chunk-vendors.be60d3b3.css" rel="stylesheet"><link href="css/index.438e06ca.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but zyplayer-db-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.ce4976ca.js"></script><script src="js/index.2e4681ba.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@
"@antv/x6": "^1.25.0", "@antv/x6": "^1.25.0",
"@antv/x6-vue-shape": "^1.1.6", "@antv/x6-vue-shape": "^1.1.6",
"@vue/composition-api": "^1.0.4", "@vue/composition-api": "^1.0.4",
"@wchbrad/vue-easy-tree": "^1.0.12",
"axios": "^0.19.0", "axios": "^0.19.0",
"brace": "^0.11.1", "brace": "^0.11.1",
"codemirror": "^5.61.1", "codemirror": "^5.61.1",
@@ -17,7 +18,9 @@
"echarts": "^4.9.0", "echarts": "^4.9.0",
"element-ui": "^2.15.0", "element-ui": "^2.15.0",
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"node-sass": "4.14.1",
"pouchdb": "^7.1.1", "pouchdb": "^7.1.1",
"sass-loader": "8.0.2",
"sql-formatter": "^2.3.3", "sql-formatter": "^2.3.3",
"umy-ui": "^1.1.6", "umy-ui": "^1.1.6",
"vue": "^2.6.10", "vue": "^2.6.10",

View File

@@ -4,58 +4,72 @@
<router-view></router-view> <router-view></router-view>
</template> </template>
<el-container v-else> <el-container v-else>
<el-aside style="background: #fafafa;" :style="{ width: rightAsideWidth + 'px' }"> <el-aside style="background: #fafafa;overflow: hidden;" :style="{ width: rightAsideWidth + 'px' }">
<div style="padding: 10px;height: 100%;box-sizing: border-box;"> <div style="padding: 10px;height: 100%;box-sizing: border-box;">
<div style="margin-bottom: 10px;"> <div id="leftTopHeight">
<el-select v-model="choiceDatasourceGroup" @change="sourceGroupChangeEvents" size="small" filterable placeholder="请先选择分组" style="width: 100%;"> <div style="margin-bottom: 10px;">
<el-option value="" label="全部分组"></el-option> <el-select v-model="choiceDatasourceGroup" @change="sourceGroupChangeEvents" size="small"
<el-option v-for="item in datasourceGroupList" :key="item" :value="item"></el-option> filterable placeholder="请先选择分组" style="width: 100%;">
</el-select> <el-option value="" label="全部分组"></el-option>
<el-select v-model="choiceDatasourceId" @change="datasourceChangeEvents" size="small" filterable placeholder="请先选择数据源" style="width: 100%;margin-top: 10px;"> <el-option v-for="item in datasourceGroupList" :key="item" :value="item"></el-option>
<el-option v-for="item in datasourceOptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select>
</el-select> <el-select v-model="choiceDatasourceId" @change="datasourceChangeEvents" size="small"
filterable placeholder="请先选择数据源" style="width: 100%;margin-top: 10px;">
<el-option v-for="item in datasourceOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</div>
<el-menu :router="true" class="el-menu-vertical" style="height: auto;">
<el-menu-item index="/data/datasourceManage"><i class="el-icon-coin"></i>数据源管理
</el-menu-item>
<el-menu-item index="/data/executor"><i class="el-icon-video-play"></i>SQL执行器
</el-menu-item>
<el-submenu index="1">
<template slot="title">
<i class="el-icon-s-platform"></i>
<span slot="title">管理工具</span>
</template>
<el-menu-item index="/data/export"><i class="el-icon-finished"></i>数据库表导出
</el-menu-item>
<el-menu-item index="/data/transferData"><i class="el-icon-document-copy"></i>数据互导工具
</el-menu-item>
</el-submenu>
</el-menu>
</div> </div>
<el-menu :router="true" class="el-menu-vertical" style="height: auto;"> <el-input v-if="choiceDatasourceId" @focus="focusEvent" v-model="filterText"
<el-menu-item index="/data/datasourceManage"><i class="el-icon-coin"></i>数据源管理</el-menu-item> placeholder="输入关键字搜索数据库"></el-input>
<el-menu-item index="/data/executor"><i class="el-icon-video-play"></i>SQL执行器</el-menu-item> <vue-easy-tree v-if="choiceDatasourceId" :height="vueEasyTreeHeight+'px'" :style="{ height: vueEasyTreeHeight + 'px' }"
<el-submenu index="1"> :props="defaultProps" :data="databaseList" @node-click="handleNodeClick"
<template slot="title"> ref="databaseTree" highlight-current empty-text=""
<i class="el-icon-s-platform"></i> :default-expanded-keys="databaseExpandedKeys"
<span slot="title">管理工具</span> :filter-node-method="filterNode"
</template> node-key="id" @node-expand="handleNodeExpand"
<el-menu-item index="/data/export"><i class="el-icon-finished"></i>数据库表导出</el-menu-item> v-loading="databaseListLoading"
<el-menu-item index="/data/transferData"><i class="el-icon-document-copy"></i>数据互导工具</el-menu-item> element-loading-text="数据库信息加载中"
</el-submenu> class="database-list-tree">
</el-menu>
<el-input v-if="choiceDatasourceId" v-model="filterText" placeholder="输入关键字搜索数据库" ></el-input>
<el-tree v-if="choiceDatasourceId"
:props="defaultProps" :data="databaseList" @node-click="handleNodeClick"
ref="databaseTree" highlight-current empty-text=""
:default-expanded-keys="databaseExpandedKeys"
:filter-node-method="filterNode"
node-key="id" @node-expand="handleNodeExpand"
v-loading="databaseListLoading"
element-loading-text="数据库信息加载中"
class="database-list-tree">
<div slot-scope="{node, data}"> <div slot-scope="{node, data}">
<span v-if="data.needLoad"><i class="el-icon-loading"></i></span> <span v-if="data.needLoad"><i class="el-icon-loading"></i></span>
<span v-else> <span v-else>
{{node.label}} {{ node.label }}
<el-tooltip v-if="!!data.comment" effect="dark" :content="data.comment" placement="top-start" :open-delay="600"> <el-tooltip v-if="!!data.comment" effect="dark" :content="data.comment"
<span style="color: #aaa;">-{{data.comment}}</span> placement="top-start" :open-delay="600">
<span style="color: #aaa;">-{{ data.comment }}</span>
</el-tooltip> </el-tooltip>
<el-dropdown v-if="data.type == 1" @command="databaseActionDropdown"> <el-dropdown v-if="data.type == 1" @command="databaseActionDropdown">
<i class="el-icon-more" @click.stop=""></i> <i class="el-icon-more" @click.stop=""></i>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-coin" :command="{command: 'procedure', node: node}">函数管理</el-dropdown-item> <el-dropdown-item icon="el-icon-coin"
<el-dropdown-item icon="el-icon-refresh" :command="{command: 'refresh', node: node}">刷新</el-dropdown-item> :command="{command: 'procedure', node: node}">函数管理</el-dropdown-item>
<el-dropdown-item icon="el-icon-refresh"
:command="{command: 'refresh', node: node}">刷新</el-dropdown-item>
<!--<el-dropdown-item icon="el-icon-upload2" :command="{command: 'upload', node: node}">导入</el-dropdown-item>--> <!--<el-dropdown-item icon="el-icon-upload2" :command="{command: 'upload', node: node}">导入</el-dropdown-item>-->
<el-dropdown-item icon="el-icon-download" :command="{command: 'download', node: node}">数据导出</el-dropdown-item> <el-dropdown-item icon="el-icon-download"
:command="{command: 'download', node: node}">数据导出</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</span> </span>
</div> </div>
</el-tree> </vue-easy-tree>
</div> </div>
</el-aside> </el-aside>
<div ref="rightResize" class="right-resize"> <div ref="rightResize" class="right-resize">
@@ -63,9 +77,10 @@
</div> </div>
<el-container> <el-container>
<el-header> <el-header>
<span class="header-right-user-name">{{userSelfInfo.userName}}</span> <span class="header-right-user-name">{{ userSelfInfo.userName }}</span>
<el-dropdown @command="userSettingDropdown" trigger="click"> <el-dropdown @command="userSettingDropdown" trigger="click">
<i class="el-icon-setting" style="margin-right: 15px; font-size: 12px;cursor: pointer;color: #fff;"> </i> <i class="el-icon-setting"
style="margin-right: 15px; font-size: 12px;cursor: pointer;color: #fff;"> </i>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="console">控制台</el-dropdown-item> <el-dropdown-item command="console">控制台</el-dropdown-item>
<el-dropdown-item command="aboutDoc" divided>关于</el-dropdown-item> <el-dropdown-item command="aboutDoc" divided>关于</el-dropdown-item>
@@ -86,319 +101,370 @@
</template> </template>
<script> <script>
import userApi from './common/api/user' import userApi from './common/api/user'
import datasourceApi from './common/api/datasource' import datasourceApi from './common/api/datasource'
import aboutDialog from './views/common/AboutDialog' import aboutDialog from './views/common/AboutDialog'
export default { export default {
data() { data() {
return { return {
filterText: '', filterText: '',
isCollapse: false, isCollapse: false,
userSelfInfo: {}, userSelfInfo: {},
// 数据源相关 // 数据源相关
datasourceOptions: [], datasourceOptions: [],
datasourceList: [], datasourceList: [],
datasourceGroupList: [], datasourceGroupList: [],
choiceDatasourceId: "", choiceDatasourceId: "",
choiceDatasourceGroup: "", choiceDatasourceGroup: "",
defaultProps: {children: 'children', label: 'name'}, defaultProps: {children: 'children', label: 'name'},
// 页面展示相关 // 页面展示相关
databaseList: [], databaseList: [],
databaseListLoading: false, databaseListLoading: false,
databaseExpandedKeys: [], databaseExpandedKeys: [],
rightAsideWidth: 300, rightAsideWidth: 300,
vueEasyTreeHeight: '',
}
},
watch: {
filterText(val) {
this.$refs.databaseTree.filter(val);
}
},
computed: {
fullscreen() {
return this.$store.state.global.fullscreen;
}
},
components: {
'about-dialog': aboutDialog
},
mounted: function () {
this.getSelfUserInfo();
this.loadDatasourceList();
this.dragChangeRightAsideWidth();
//浏览器页面高度
let winHeight = window.innerHeight;
let leftTopHeight = document.getElementById('leftTopHeight').offsetHeight;
this.vueEasyTreeHeight = winHeight - leftTopHeight -50;
},
beforeDestroy() {
// 移除滚动事件监听
this.$refs.scrollContainer.removeEventListener('scroll', this.handleScroll)
},
methods: {
userSettingDropdown(command) {
console.log("command:" + command);
if (command == 'userSignOut') {
this.userSignOut();
} else if (command == 'aboutDoc') {
this.$refs.aboutDialog.show();
} else if (command == 'myInfo') {
this.$router.push({path: '/user/myInfo'});
} else if (command == 'console') {
window.open(process.env.VUE_APP_BASE_API, '_blank');
} else {
this.$message.warning("功能暂未开放");
} }
}, },
watch: { userSignOut() {
filterText(val) { userApi.userLogout().then(() => {
this.$refs.databaseTree.filter(val); location.reload();
});
},
getSelfUserInfo() {
userApi.getSelfUserInfo().then(json => {
this.userSelfInfo = json.data;
});
},
sourceGroupChangeEvents() {
let datasourceOptions = [];
this.datasourceList.forEach(item => {
if (!this.choiceDatasourceGroup || this.choiceDatasourceGroup == item.groupName) {
datasourceOptions.push({label: item.name, value: item.id});
}
});
this.datasourceOptions = datasourceOptions;
this.choiceDatasourceId = '';
this.databaseList = [];
this.filterText = "";
},
datasourceChangeEvents() {
let choiceSource = this.datasourceList.find(item => item.id == this.choiceDatasourceId);
this.loadDatabaseList(this.choiceDatasourceId, choiceSource.name);
this.filterText = "";
},
handleNodeClick(node) {
if (node.type == 1) {
this.nowClickPath = {
sourceId: this.choiceDatasourceId,
host: node.host,
dbName: node.dbName,
tableName: node.tableName
};
this.$router.push({path: '/table/database', query: this.nowClickPath});
} else if (node.type == 2) {
this.nowClickPath = {
sourceId: this.choiceDatasourceId,
host: node.host,
dbName: node.dbName,
tableName: node.tableName
};
this.$router.push({path: '/table/info', query: this.nowClickPath});
} }
}, },
computed: { handleNodeExpand(nodeData, node) {
fullscreen () { if (nodeData.children.length > 0 && nodeData.children[0].needLoad) {
return this.$store.state.global.fullscreen; if (nodeData.type === 1) {
this.loadGetTableList(nodeData, node);
}
} }
}, },
components: { databaseActionDropdown(param) {
'about-dialog': aboutDialog if (param.command == 'refresh') {
param.node.loading = true;
param.node.data.children = [];
this.loadGetTableList(param.node.data, param.node, () => {
setTimeout(() => param.node.loading = false, 500);
});
} else if (param.command == 'procedure') {
let nodeData = param.node.data;
let procedureParam = {sourceId: this.choiceDatasourceId, dbName: nodeData.dbName, host: nodeData.host};
this.$router.push({path: '/procedure/list', query: procedureParam});
} else if (param.command == 'download') {
let nodeData = param.node.data;
let procedureParam = {sourceId: this.choiceDatasourceId, dbName: nodeData.dbName};
this.$router.push({path: '/data/export', query: procedureParam});
} else {
this.$message.warning("暂未支持的选项");
}
}, },
mounted: function () { loadGetTableList(nodeData, node, callback) {
this.getSelfUserInfo(); datasourceApi.tableList({sourceId: this.choiceDatasourceId, dbName: nodeData.dbName}).then(json => {
this.loadDatasourceList(); let pathIndex = [];
this.dragChangeRightAsideWidth(); let result = json.data || [];
for (let i = 0; i < result.length; i++) {
let item = {
id: nodeData.host + "_" + nodeData.dbName + "_" + result[i].tableName, host: nodeData.host,
dbName: nodeData.dbName, tableName: result[i].tableName, name: result[i].tableName, type: 2,
comment: result[i].tableComment
};
pathIndex.push(item);
}
nodeData.children = pathIndex;
//更新当前节点的子节点
node.childNodes = [];
this.$refs.databaseTree.updateKeyChildren(node.key, nodeData.children);
if (typeof callback == 'function') {
callback(pathIndex);
}
});
}, },
methods: { loadDatasourceList() {
userSettingDropdown(command) { datasourceApi.datasourceList({}).then(json => {
console.log("command:" + command); this.datasourceList = json.data || [];
if (command == 'userSignOut') { if (this.datasourceList.length <= 0) {
this.userSignOut();
} else if (command == 'aboutDoc') {
this.$refs.aboutDialog.show();
} else if (command == 'myInfo') {
this.$router.push({path: '/user/myInfo'});
} else if (command == 'console') {
window.open(process.env.VUE_APP_BASE_API, '_blank');
} else {
this.$message.warning("功能暂未开放");
}
},
userSignOut() {
userApi.userLogout().then(() => {
location.reload();
});
},
getSelfUserInfo() {
userApi.getSelfUserInfo().then(json=>{
this.userSelfInfo = json.data;
});
},
sourceGroupChangeEvents() {
let datasourceOptions = [];
this.datasourceList.forEach(item => {
if (!this.choiceDatasourceGroup || this.choiceDatasourceGroup == item.groupName) {
datasourceOptions.push({label: item.name, value: item.id});
}
});
this.datasourceOptions = datasourceOptions;
this.choiceDatasourceId = '';
this.databaseList = [];
},
datasourceChangeEvents() {
let choiceSource = this.datasourceList.find(item => item.id == this.choiceDatasourceId);
this.loadDatabaseList(this.choiceDatasourceId, choiceSource.name);
},
handleNodeClick(node) {
//console.log("点击节点:", node);
// 执行器里面点击库表不跳转页面
// if (this.$router.currentRoute.path == "/data/executor") {
// return;
// }
if (node.type == 1) {
this.nowClickPath = {sourceId: this.choiceDatasourceId, host: node.host, dbName: node.dbName, tableName: node.tableName};
this.$router.push({path: '/table/database', query: this.nowClickPath});
} else if (node.type == 2) {
this.nowClickPath = {sourceId: this.choiceDatasourceId, host: node.host, dbName: node.dbName, tableName: node.tableName};
this.$router.push({path: '/table/info', query: this.nowClickPath});
}
},
handleNodeExpand(node) {
if (node.children.length > 0 && node.children[0].needLoad) {
if (node.type == 1) {
this.loadGetTableList(node);
}
}
},
databaseActionDropdown(param) {
if (param.command == 'refresh') {
param.node.loading = true;
param.node.data.children = [];
this.loadGetTableList(param.node.data, () => {
setTimeout(() => param.node.loading = false, 500);
});
} else if (param.command == 'procedure') {
let nodeData = param.node.data;
let procedureParam = {sourceId: this.choiceDatasourceId,dbName: nodeData.dbName, host: nodeData.host};
this.$router.push({path: '/procedure/list', query: procedureParam});
} else if (param.command == 'download') {
let nodeData = param.node.data;
let procedureParam = {sourceId: this.choiceDatasourceId, dbName: nodeData.dbName};
this.$router.push({path: '/data/export', query: procedureParam});
} else {
this.$message.warning("暂未支持的选项");
}
},
loadGetTableList(node, callback) {
datasourceApi.tableList({sourceId: this.choiceDatasourceId, dbName: node.dbName}).then(json => {
let pathIndex = [];
let result = json.data || [];
for (let i = 0; i < result.length; i++) {
let item = {
id: node.host + "_" + node.dbName + "_" + result[i].tableName, host: node.host,
dbName: node.dbName, tableName: result[i].tableName, name: result[i].tableName, type: 2,
comment: result[i].tableComment
};
// item.children = [{label: '', needLoad: true}];// 初始化一个对象,点击展开时重新查询加载
pathIndex.push(item);
}
node.children = pathIndex;
if (typeof callback == 'function') {
callback(pathIndex);
}
});
},
loadDatasourceList() {
datasourceApi.datasourceList({}).then(json => {
this.datasourceList = json.data || [];
if (this.datasourceList.length <= 0) {
return;
}
let datasourceOptions = [];
this.datasourceList.forEach(item => datasourceOptions.push({label: item.name, value: item.id}));
this.datasourceOptions = datasourceOptions;
let datasourceGroupList = [];
this.datasourceList.filter(item => !!item.groupName).forEach(item => datasourceGroupList.push(item.groupName));
this.datasourceGroupList = Array.from(new Set(datasourceGroupList));
});
},
loadDatabaseList(sourceId, host) {
return new Promise((resolve, reject) => {
this.databaseList = [];
this.databaseListLoading = true;
datasourceApi.databaseList({sourceId: sourceId}).then(json => {
this.databaseListLoading = false;
let result = json.data || [];
let pathIndex = [];
let children = [];
for (let i = 0; i < result.length; i++) {
let item = {
id: host + "_" + result[i].dbName, host: host, dbName: result[i].dbName,
name: result[i].dbName, type: 1
};
item.children = [{label: '', needLoad: true}];// 初始化一个对象,点击展开时重新查询加载
children.push(item);
}
pathIndex.push({id: host, host: host, name: host, children: children});
this.databaseList = pathIndex;
resolve();
}).catch(e => {
this.choiceDatasourceId = '';
this.databaseListLoading = false;
});
});
},
initLoadDataList(param) {
if (this.databaseList.length > 0) {
return; return;
} }
this.choiceDatasourceId = parseInt(param.sourceId); let datasourceOptions = [];
this.loadDatabaseList(param.sourceId, param.host).then(() => { this.datasourceList.forEach(item => datasourceOptions.push({label: item.name, value: item.id}));
this.databaseExpandedKeys = [param.host]; this.datasourceOptions = datasourceOptions;
}); let datasourceGroupList = [];
}, this.datasourceList.filter(item => !!item.groupName).forEach(item => datasourceGroupList.push(item.groupName));
dragChangeRightAsideWidth: function() { this.datasourceGroupList = Array.from(new Set(datasourceGroupList));
// 保留this引用 });
let resize = this.$refs.rightResize; },
let resizeBar = this.$refs.rightResizeBar; loadDatabaseList(sourceId, host) {
resize.onmousedown = e => { return new Promise((resolve, reject) => {
let startX = e.clientX; this.databaseList = [];
// 颜色改变提醒 this.databaseListLoading = true;
resize.style.background = "#ccc"; datasourceApi.databaseList({sourceId: sourceId}).then(json => {
resizeBar.style.background = "#aaa"; this.databaseListLoading = false;
resize.left = resize.offsetLeft; let result = json.data || [];
document.onmousemove = e2 => { let pathIndex = [];
// 计算并应用位移量 let children = [];
let endX = e2.clientX; for (let i = 0; i < result.length; i++) {
let moveLen = startX - endX; let item = {
if ((moveLen < 0 && this.rightAsideWidth < 600) || (moveLen > 0 && this.rightAsideWidth > 200)) { id: host + "_" + result[i].dbName, host: host, dbName: result[i].dbName,
startX = endX; name: result[i].dbName, type: 1
this.rightAsideWidth -= moveLen; };
if (this.rightAsideWidth < 200) { item.children = [{label: '', needLoad: true}];// 初始化一个对象,点击展开时重新查询加载
this.rightAsideWidth = 200; children.push(item);
}
}
};
document.onmouseup = () => {
// 颜色恢复
resize.style.background = "#fafafa";
resizeBar.style.background = "#ccc";
document.onmousemove = null;
document.onmouseup = null;
};
return false;
};
},
filterNode(value, data, node) {
if (node.level === 3&&node.data.needLoad) {
if(!node.parent){
return false;
} }
let pnode = node.parent.data; pathIndex.push({id: host, host: host, name: host, children: children});
datasourceApi.tableList({sourceId: this.choiceDatasourceId, dbName: pnode.dbName}).then(json => { this.databaseList = pathIndex;
let pathIndex = []; resolve();
let result = json.data || []; }).catch(e => {
for (let i = 0; i < result.length; i++) { this.choiceDatasourceId = '';
let item = { this.databaseListLoading = false;
id: pnode.host + "_" + pnode.dbName + "_" + result[i].tableName, host: pnode.host, });
dbName: pnode.dbName, tableName: result[i].tableName, name: result[i].tableName, type: 2, });
comment: result[i].tableComment },
}; initLoadDataList(param) {
pathIndex.push(item); if (this.databaseList.length > 0) {
} return;
pnode.children = pathIndex;
this.filterNode(value, data, node);
});
return false;
}
if (!value) return true;
return data.name.toLowerCase().indexOf(value.toLowerCase()) !== -1;
} }
this.choiceDatasourceId = parseInt(param.sourceId);
this.loadDatabaseList(param.sourceId, param.host).then(() => {
this.databaseExpandedKeys = [param.host];
});
},
dragChangeRightAsideWidth: function () {
// 保留this引用
let resize = this.$refs.rightResize;
let resizeBar = this.$refs.rightResizeBar;
resize.onmousedown = e => {
let startX = e.clientX;
// 颜色改变提醒
resize.style.background = "#ccc";
resizeBar.style.background = "#aaa";
resize.left = resize.offsetLeft;
document.onmousemove = e2 => {
// 计算并应用位移量
let endX = e2.clientX;
let moveLen = startX - endX;
if ((moveLen < 0 && this.rightAsideWidth < 600) || (moveLen > 0 && this.rightAsideWidth > 200)) {
startX = endX;
this.rightAsideWidth -= moveLen;
if (this.rightAsideWidth < 200) {
this.rightAsideWidth = 200;
}
}
};
document.onmouseup = () => {
// 颜色恢复
resize.style.background = "#fafafa";
resizeBar.style.background = "#ccc";
document.onmousemove = null;
document.onmouseup = null;
};
return false;
};
},
focusEvent() {
let nodes = this.$refs.databaseTree.root.childNodes;
nodes.forEach(node => {
let childNodes = node.childNodes;
childNodes.forEach(childNode => {
this.handleNodeExpand(childNode.data, childNode);
});
});
},
filterNode(value, data, node) {
if (!value) return true;
return data.name.toLowerCase().indexOf(value.toLowerCase()) !== -1;
} }
} }
}
</script> </script>
<style> <style>
html, body { html, body {
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 100%; height: 100%;
} }
#app, .el-container, .el-menu {
height: 100%; #app, .el-container, .el-menu {
height: 100%;
font-size: 12px; font-size: 12px;
} }
.el-header {
background-color: #1D4E89 !important;
}
.database-list-tree{background-color: #fafafa;overflow-x: auto;min-height: 150px;}
.database-list-tree .el-loading-mask{background-color: #fafafa;}
.database-list-tree .el-tree-node>.el-tree-node__children {
overflow: unset;
}
.header-right-user-name{color: #fff;padding-right: 5px;}
.el-menu-vertical{border-right: 0;background: #fafafa}
.el-menu-item, .el-submenu__title{font-size: 12px;}
.el-menu-vertical .el-menu{background: #fafafa;}
.el-header {background-color: #409EFF; color: #333; line-height: 40px; text-align: right;height: 40px !important;}
.el-tree-node__content{} .el-header {
.el-tree-node__content .el-icon-more{margin-left: 5px;color: #606266;font-size: 12px; display: none;padding: 2px 5px;} background-color: #1D4E89 !important;
.el-tree-node__content:hover .el-icon-more{display: inline-block;} }
.right-resize { .database-list-tree {
width: 5px; background-color: #fafafa;
height: 100%; overflow-x: auto;
cursor: w-resize; min-height: 150px;
background: #fafafa; }
}
.right-resize i{ .database-list-tree .el-loading-mask {
margin-top: 300px; background-color: #fafafa;
width: 5px; }
height: 35px;
display: inline-block; .database-list-tree .el-tree-node > .el-tree-node__children {
word-wrap: break-word; overflow: unset;
word-break: break-all; }
line-height: 8px;
border-radius: 5px; .header-right-user-name {
background: #ccc; color: #fff;
color: #888; padding-right: 5px;
text-align: center; }
}
::-webkit-scrollbar-track { .el-menu-vertical {
border-right: 0;
background: #fafafa
}
.el-menu-item, .el-submenu__title {
font-size: 12px;
}
.el-menu-vertical .el-menu {
background: #fafafa;
}
.el-header {
background-color: #409EFF;
color: #333;
line-height: 40px;
text-align: right;
height: 40px !important;
}
.el-tree-node__content {
}
.el-tree-node__content .el-icon-more {
margin-left: 5px;
color: #606266;
font-size: 12px;
display: none;
padding: 2px 5px;
}
.el-tree-node__content:hover .el-icon-more {
display: inline-block;
}
.right-resize {
width: 5px;
height: 100%;
cursor: w-resize;
background: #fafafa;
}
.right-resize i {
margin-top: 300px;
width: 5px;
height: 35px;
display: inline-block;
word-wrap: break-word;
word-break: break-all;
line-height: 8px;
border-radius: 5px;
background: #ccc;
color: #888;
text-align: center;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1); background: rgba(0, 0, 0, 0.1);
border-radius: 10px; border-radius: 10px;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
-webkit-appearance: none; -webkit-appearance: none;
width: 10px; width: 10px;
height: 10px; height: 10px;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
cursor: pointer; cursor: pointer;
border-radius: 5px; border-radius: 5px;
background: rgba(0, 0, 0, 0.15); background: rgba(0, 0, 0, 0.15);
transition: color 0.2s ease; transition: color 0.2s ease;
} }
</style> </style>

View File

@@ -3,6 +3,8 @@ import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'; import 'element-ui/lib/theme-chalk/index.css';
import UmyUi from 'umy-ui'; import UmyUi from 'umy-ui';
import 'umy-ui/lib/theme-chalk/index.css'; import 'umy-ui/lib/theme-chalk/index.css';
import VueEasyTree from "@wchbrad/vue-easy-tree";
import "@wchbrad/vue-easy-tree/src/assets/index.scss"
import App from './App.vue'; import App from './App.vue';
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
@@ -22,6 +24,7 @@ Vue.use(ElementUI,{
size:'small' size:'small'
}); });
Vue.use(UmyUi); Vue.use(UmyUi);
Vue.use(VueEasyTree)
Vue.use(VueRouter); Vue.use(VueRouter);
Vue.use(VueAxios, axios); Vue.use(VueAxios, axios);
Vue.use(vueHljs); Vue.use(vueHljs);

View File

@@ -718,6 +718,12 @@ export default {
} }
}, },
dragChangeTopHeight: function () { dragChangeTopHeight: function () {
//浏览器页面高度
let winHeight = window.innerHeight;
//主体高度
let bodyHeight = winHeight - 82;
this.rightBodyHeight = bodyHeight;
let bodyTopHeight = bodyHeight * 0.75;
// 保留this引用 // 保留this引用
let resize = this.$refs.topResize; let resize = this.$refs.topResize;
let resizeBar = this.$refs.topResizeBar; let resizeBar = this.$refs.topResizeBar;
@@ -731,14 +737,14 @@ export default {
// 计算并应用位移量 // 计算并应用位移量
let endY = e2.clientY; let endY = e2.clientY;
let moveLen = startY - endY; let moveLen = startY - endY;
if ((moveLen < 0 && this.rightBodyTopHeight < 480) || (moveLen > 0 && this.rightBodyTopHeight > 100)) { if ((moveLen < 0 && this.rightBodyTopHeight < bodyTopHeight) || (moveLen > 0 && this.rightBodyTopHeight > 100)) {
startY = endY; startY = endY;
this.rightBodyTopHeight -= moveLen; this.rightBodyTopHeight -= moveLen;
if (this.rightBodyTopHeight < 100) { if (this.rightBodyTopHeight < 100) {
this.rightBodyTopHeight = 100; this.rightBodyTopHeight = 100;
} }
if (this.rightBodyTopHeight > 480) { if (this.rightBodyTopHeight > bodyTopHeight) {
this.rightBodyTopHeight = 480; this.rightBodyTopHeight = bodyTopHeight;
} }
this.elementHeightCalculation(); this.elementHeightCalculation();
} }