db模块tab页面增加右键菜单

This commit is contained in:
diant
2023-05-24 16:44:29 +08:00
parent 960eccd165
commit e456d4e95e
10 changed files with 671 additions and 462 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.108f40b4.css" rel="preload" as="style"><link href="js/chunk-vendors.6270548d.js" rel="preload" as="script"><link href="js/index.ddad9e6e.js" rel="preload" as="script"><link href="css/chunk-vendors.2fa4c9b3.css" rel="stylesheet"><link href="css/index.108f40b4.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.ddad9e6e.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.2fa4c9b3.css" rel="preload" as="style"><link href="css/index.acbccf83.css" rel="preload" as="style"><link href="js/chunk-vendors.6270548d.js" rel="preload" as="script"><link href="js/index.790e04cd.js" rel="preload" as="script"><link href="css/chunk-vendors.2fa4c9b3.css" rel="stylesheet"><link href="css/index.acbccf83.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.790e04cd.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

View File

@@ -1,18 +1,38 @@
<template> <template>
<div> <div>
<el-tabs v-model="activePage" type="card" closable @tab-click="changePage" @tab-remove="removePageTab" style="padding: 5px 10px 0;"> <el-tabs v-model="activePage" type="card" closable @tab-click="changePage" @tab-remove="removePageTab"
<el-tab-pane :label="pageTabNameMap[item.fullPath]||item.name" :name="getRouteRealPath(item)" :fullPath="item.fullPath" :key="item.fullPath" v-for="item in pageList"/> @contextmenu.prevent.native="openContextMenu($event)" style="padding: 5px 10px 0;">
<el-tab-pane :label="pageTabNameMap[item.fullPath]||item.name" :name="getRouteRealPath(item)"
:fullPath="item.fullPath" :key="item.fullPath" v-for="item in pageList"/>
</el-tabs> </el-tabs>
<keep-alive> <keep-alive>
<router-view v-on:listenToChildEvent = "getDatafromChild" :key="$route.fullPath" @initLoadDataList="initLoadDataList" @loadDatasourceList="loadDatasourceList"/> <router-view v-on:listenToChildEvent="getDatafromChild" :key="$route.fullPath"
@initLoadDataList="initLoadDataList" @loadDatasourceList="loadDatasourceList"/>
</keep-alive> </keep-alive>
<ul v-show="contextMenuVisible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
<!--<li @click="curTabReload()"><el-button type="text" size="mini">重新加载</el-button></li>-->
<li @click="closeAllTabs()">
<el-button type="text" size="mini">关闭所有</el-button>
</li>
<li @click="closeOtherTabs('left')">
<el-button type="text" size="mini">关闭左边</el-button>
</li>
<li @click="closeOtherTabs('right')">
<el-button type="text" size="mini">关闭右边</el-button>
</li>
<li @click="closeOtherTabs('other')">
<el-button type="text" size="mini">关闭其他</el-button>
</li>
</ul>
</div> </div>
</template> </template>
<script> <script>
import datasourceApi from "@/common/api/datasource"; import datasourceApi from "@/common/api/datasource";
export default { export default {
name: 'PageTableView', name: 'PageTableView',
components: {}, components: {},
data() { data() {
@@ -25,25 +45,28 @@
ignoreParamPath: [ ignoreParamPath: [
"/data/export", "/data/export",
], ],
contextMenuVisible: false,
left: 0,
top: 0,
} }
}, },
computed: { computed: {
pageTabNameMap () { pageTabNameMap() {
return this.$store.state.global.pageTabNameMap; return this.$store.state.global.pageTabNameMap;
} }
}, },
created() { created() {
let {name, path, fullPath} = this.$route; let {name, path, fullPath} = this.$route;
//sql执行器tab页名称动态变化 //sql执行器tab页名称动态变化
if(path === '/data/executor'){ if (path === '/data/executor') {
let database = this.$route.query.database; let database = this.$route.query.database;
let datasourceId = this.$route.query.datasourceId; let datasourceId = this.$route.query.datasourceId;
if(datasourceId){ if (datasourceId) {
datasourceApi.datasource({sourceId: datasourceId}).then(json => { datasourceApi.datasource({sourceId: datasourceId}).then(json => {
let dataname = json.data.name; let dataname = json.data.name;
let groupName = json.data.name; let groupName = json.data.name;
if(dataname){ if (dataname) {
name = name+"( "+dataname+"["+database+"] )" name = name + "( " + dataname + "[" + database + "] )"
} }
this.pageList.push({name, path, fullPath}); this.pageList.push({name, path, fullPath});
let activePage = this.getRouteRealPath(this.$route); let activePage = this.getRouteRealPath(this.$route);
@@ -52,22 +75,27 @@
this.$router.push(this.$route.fullPath); this.$router.push(this.$route.fullPath);
}) })
return false; return false;
}else{ } else {
datasourceApi.datasourceList({}).then(json => { datasourceApi.datasourceList({}).then(json => {
this.datasourceList = json.data || []; this.datasourceList = json.data || [];
if (this.datasourceList.length > 0) { if (this.datasourceList.length > 0) {
let dataname = this.datasourceList[0].name; let dataname = this.datasourceList[0].name;
if(this.datasourceList[0].id){ if (this.datasourceList[0].id) {
datasourceApi.databaseList({sourceId: this.datasourceList[0].id}).then(json => { datasourceApi.databaseList({sourceId: this.datasourceList[0].id}).then(json => {
if (json.data.length > 0) { if (json.data.length > 0) {
// 排除系统库 // 排除系统库
let sysDbName = ["information_schema", "master", "model", "msdb", "tempdb"]; let sysDbName = ["information_schema", "master", "model", "msdb", "tempdb"];
let notSysDbItem = json.data.find(item => sysDbName.indexOf(item.dbName) < 0); let notSysDbItem = json.data.find(item => sysDbName.indexOf(item.dbName) < 0);
let choiceDatabase = (!!notSysDbItem) ? notSysDbItem.dbName : json.data[0].dbName; let choiceDatabase = (!!notSysDbItem) ? notSysDbItem.dbName : json.data[0].dbName;
if(dataname&&choiceDatabase){ if (dataname && choiceDatabase) {
name = name+"( "+dataname+"["+choiceDatabase+"] )" name = name + "( " + dataname + "[" + choiceDatabase + "] )"
} }
this.$router.replace({ query: { datasourceId: this.datasourceList[0].id,database:choiceDatabase } }) this.$router.replace({
query: {
datasourceId: this.datasourceList[0].id,
database: choiceDatabase
}
})
} }
}) })
} }
@@ -91,41 +119,44 @@
let {name, path, fullPath} = newRoute; let {name, path, fullPath} = newRoute;
this.pageList.push({name, path, fullPath}); this.pageList.push({name, path, fullPath});
//sql执行器tab页名称动态变化 //sql执行器tab页名称动态变化
if(path === '/data/executor'){ if (path === '/data/executor') {
let database = newRoute.query.database; let database = newRoute.query.database;
let datasourceId = newRoute.query.datasourceId; let datasourceId = newRoute.query.datasourceId;
if(datasourceId) { if (datasourceId) {
datasourceApi.datasource({sourceId: datasourceId}).then(json => { datasourceApi.datasource({sourceId: datasourceId}).then(json => {
let dataname = json.data.name; let dataname = json.data.name;
let groupName = json.data.groupName; let groupName = json.data.groupName;
if (dataname) { if (dataname) {
name = name+"( "+dataname+"["+database+"] )" name = name + "( " + dataname + "[" + database + "] )"
} }
//this.pageList.push({name, path, fullPath}); //this.pageList.push({name, path, fullPath});
let pageRoute = this.pageList.find(item => this.getRouteRealPath(item) === activePage); let pageRoute = this.pageList.find(item => this.getRouteRealPath(item) === activePage);
pageRoute.name = name; pageRoute.name = name;
}) })
}else{ } else {
datasourceApi.datasourceList({}).then(json => { datasourceApi.datasourceList({}).then(json => {
this.datasourceList = json.data || []; this.datasourceList = json.data || [];
if (this.datasourceList.length > 0) { if (this.datasourceList.length > 0) {
let dataname = this.datasourceList[0].name; let dataname = this.datasourceList[0].name;
if(this.datasourceList[0].id){ if (this.datasourceList[0].id) {
datasourceApi.databaseList({sourceId: this.datasourceList[0].id}).then(json => { datasourceApi.databaseList({sourceId: this.datasourceList[0].id}).then(json => {
if (json.data.length > 0) { if (json.data.length > 0) {
// 排除系统库 // 排除系统库
let sysDbName = ["information_schema", "master", "model", "msdb", "tempdb"]; let sysDbName = ["information_schema", "master", "model", "msdb", "tempdb"];
let notSysDbItem = json.data.find(item => sysDbName.indexOf(item.dbName) < 0); let notSysDbItem = json.data.find(item => sysDbName.indexOf(item.dbName) < 0);
let choiceDatabase = (!!notSysDbItem) ? notSysDbItem.dbName : json.data[0].dbName; let choiceDatabase = (!!notSysDbItem) ? notSysDbItem.dbName : json.data[0].dbName;
if(dataname&&choiceDatabase){ if (dataname && choiceDatabase) {
name = name+"( "+dataname+"["+choiceDatabase+"] )" name = name + "( " + dataname + "[" + choiceDatabase + "] )"
} }
console.log("this.pageList+++++++++"+JSON.stringify(this.pageList)) this.pageList.splice(this.pageList.findIndex(item => item.fullPath === path), 1);
this.pageList.splice(this.pageList.findIndex(item => item.fullPath === path),1); this.linkList.splice(this.linkList.findIndex(item => item === path), 1);
this.linkList.splice(this.linkList.findIndex(item => item === path),1); this.$router.replace({
console.log("this.pageList+++++++++"+JSON.stringify(this.pageList)) query: {
this.$router.replace({ query: { datasourceId: this.datasourceList[0].id,database:choiceDatabase } }) datasourceId: this.datasourceList[0].id,
database: choiceDatabase
}
})
} }
}) })
} }
@@ -138,9 +169,16 @@
//let pageRoute = this.pageList.find(item => this.getRouteRealPath(item) === activePage); //let pageRoute = this.pageList.find(item => this.getRouteRealPath(item) === activePage);
//pageRoute.fullPath = newRoute.fullPath; //pageRoute.fullPath = newRoute.fullPath;
}, },
contextMenuVisible(value) {
if (value) {
document.body.addEventListener('click', this.closeContextMenu)
} else {
document.body.removeEventListener('click', this.closeContextMenu)
}
}
}, },
methods: { methods: {
getDatafromChild(data){ getDatafromChild(data) {
this.datasourceList = data; this.datasourceList = data;
}, },
initLoadDataList(param) { initLoadDataList(param) {
@@ -177,24 +215,136 @@
this.$router.push(this.activePage); this.$router.push(this.activePage);
} }
}, },
//tab栏右键菜单
openContextMenu(e) {
let obj = e.srcElement ? e.srcElement : e.target;
if (obj.id) {
let currentContextTabId = obj.id.split("-")[1];
this.contextMenuVisible = true;
this.$store.commit("saveCurContextTabId", currentContextTabId);
this.left = e.clientX;
this.top = e.clientY + 10;
}
},
//刷新当前页
curTabReload() {
let currTabIndex = 0;
let curContextTabId = this.$store.state.tagsView.curContextTabId;
for (let i = 0; i < this.pageList.length; i++) {
if (curContextTabId === this.pageList[i].fullPath) {
currTabIndex = i;
break;
} }
} }
this.activePage = this.linkList[currTabIndex];
this.$router.push(this.activePage);
this.closeContextMenu()
},
// 关闭所有标签页
closeAllTabs() {
//删除所有tab标签
this.linkList.splice(0, this.linkList.length)
this.pageList.splice(0, this.pageList.length)
this.$router.replace({query: {}})
this.closeContextMenu()
},
// 关闭其它标签页
closeOtherTabs(par) {
let currTabIndex = 0;
let curContextTabId = this.$store.state.tagsView.curContextTabId;
for (let i = 0; i < this.pageList.length; i++) {
if (curContextTabId === this.pageList[i].fullPath) {
currTabIndex = i;
break;
}
}
switch (par) {
case "left": {
//删除左侧tab标签
this.pageList.splice(0, currTabIndex);
this.linkList.splice(0, currTabIndex);
this.activePage = this.linkList[0];
this.$router.push(this.activePage);
break;
}
case "right": {
//删除右侧tab标签
this.pageList.splice(currTabIndex + 1, this.pageList.length);
this.linkList.splice(currTabIndex + 1, this.linkList.length);
this.activePage = this.linkList[currTabIndex];
this.$router.push(this.activePage);
break;
}
case "other": {
//删除其他所有tab标签
this.pageList.splice(0, currTabIndex);
this.linkList.splice(0, currTabIndex);
this.pageList.splice(currTabIndex + 1, this.pageList.length);
this.linkList.splice(currTabIndex + 1, this.linkList.length);
this.activePage = this.linkList[0];
this.$router.push(this.activePage);
break;
}
}
this.closeContextMenu()
},
// 关闭contextMenu
closeContextMenu() {
this.contextMenuVisible = false;
},
}
}
</script> </script>
<style scoped> <style scoped>
/deep/ .el-tabs--card>.el-tabs__header{ /deep/ .el-tabs--card > .el-tabs__header {
margin: 0 0 5px; margin: 0 0 5px;
} }
/deep/ .el-tabs--card>.el-tabs__header .el-tabs__item{
/deep/ .el-tabs--card > .el-tabs__header .el-tabs__item {
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
} }
/deep/ .el-tabs__nav-next{
/deep/ .el-tabs__nav-next {
line-height: 33px; line-height: 33px;
font-size: 20px; font-size: 20px;
} }
/deep/ .el-tabs__nav-prev{
/deep/ .el-tabs__nav-prev {
line-height: 33px; line-height: 33px;
font-size: 20px; font-size: 20px;
} }
.contextmenu {
width: 100px;
margin: 0;
border: 1px solid #ccc;
background: #fff;
z-index: 3000;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
font-size: 14px;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.2);
}
.contextmenu li {
margin: 0;
padding: 0px 22px;
}
.contextmenu li:hover {
background: #f2f2f2;
cursor: pointer;
}
.contextmenu li button {
color: #2c3e50;
}
</style> </style>

View File

@@ -1,11 +1,13 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import global from './modules/global' import global from './modules/global'
import tagsView from './modules/tagsView'
Vue.use(Vuex); Vue.use(Vuex);
export default new Vuex.Store({ export default new Vuex.Store({
modules: { modules: {
global, global,
tagsView
} }
}); });

View File

@@ -0,0 +1,15 @@
const state = {
}
const mutations = {
// <20><><EFBFBD><EFBFBD><EFBFBD>Ҽ<EFBFBD><D2BC><EFBFBD><EFBFBD><EFBFBD>tab<61><62>id
saveCurContextTabId(state, curContextTabId) {
state.curContextTabId = curContextTabId
},
}
export default {
state,
mutations
}

View File

@@ -9,7 +9,8 @@
:description="executorDesc" :description="executorDesc"
show-icon> show-icon>
</el-alert> </el-alert>
<ace-editor v-model="sqlExecutorContent" @init="sqlExecutorInit" lang="sql" theme="monokai" width="100%" <ace-editor v-model="sqlExecutorContent" @init="sqlExecutorInit" lang="sql" theme="monokai"
width="100%"
height="60" :options="sqlEditorConfig" :source="executorSource" height="60" :options="sqlEditorConfig" :source="executorSource"
style="margin-bottom: 10px;"> style="margin-bottom: 10px;">
</ace-editor> </ace-editor>
@@ -35,10 +36,13 @@
<el-card> <el-card>
<div v-if="!!executeError" style="color: #f00;">{{ executeError }}</div> <div v-if="!!executeError" style="color: #f00;">{{ executeError }}</div>
<div v-else-if="sqlExecuting" v-loading="sqlExecuting" style="padding: 20px 0;">数据加载中...</div> <div v-else-if="sqlExecuting" v-loading="sqlExecuting" style="padding: 20px 0;">数据加载中...</div>
<div v-else-if="executeResultList.length <= 0" v-loading="sqlExecuting" style="padding: 20px 0;">暂无数据</div> <div v-else-if="executeResultList.length <= 0" v-loading="sqlExecuting" style="padding: 20px 0;">
暂无数据
</div>
<div v-else style="position: relative;"> <div v-else style="position: relative;">
<div style="position: absolute;right: 0;z-index: 1;" v-show="executeShowTable !== 'table0'"> <div style="position: absolute;right: 0;z-index: 1;" v-show="executeShowTable !== 'table0'">
<span v-show="choiceResultObj[executeShowTable] && choiceResultObj[executeShowTable].length > 0"> <span
v-show="choiceResultObj[executeShowTable] && choiceResultObj[executeShowTable].length > 0">
<el-button icon="el-icon-delete" size="small" @click="deleteCheckLine" type="danger" plain <el-button icon="el-icon-delete" size="small" @click="deleteCheckLine" type="danger" plain
style="margin-right: 10px;">删除</el-button> style="margin-right: 10px;">删除</el-button>
<!-- 复制选中行 --> <!-- 复制选中行 -->
@@ -63,7 +67,8 @@
<pre class="xxpre">{{ executeResultInfo }}</pre> <pre class="xxpre">{{ executeResultInfo }}</pre>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="'结果'+resultItem.index" :name="resultItem.name" <el-tab-pane :label="'结果'+resultItem.index" :name="resultItem.name"
v-for="(resultItem,index) in executeResultList" :key="index" v-if="!!resultItem.index"> v-for="(resultItem,index) in executeResultList" :key="index"
v-if="!!resultItem.index">
<div v-if="!!resultItem.errMsg" style="color: #f00;">{{ resultItem.errMsg }}</div> <div v-if="!!resultItem.errMsg" style="color: #f00;">{{ resultItem.errMsg }}</div>
<div v-else-if="resultItem.dataList.length <= 0" <div v-else-if="resultItem.dataList.length <= 0"
style="text-align: center; color: #aaa; padding: 20px 0;">暂无数据 style="text-align: center; color: #aaa; padding: 20px 0;">暂无数据
@@ -75,7 +80,8 @@
stripe stripe
border border
:height="height" :height="height"
style="width: 100%; margin-bottom: 5px;" class="execute-result-table" :max-height="tableMaxHeight" style="width: 100%; margin-bottom: 5px;" class="execute-result-table"
:max-height="tableMaxHeight"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
@cell-click="mouseOnFocus" @cell-click="mouseOnFocus"
@cell-mouse-leave="mouseLeave" @cell-mouse-leave="mouseLeave"
@@ -83,7 +89,8 @@
:default-sort="tableSort"> :default-sort="tableSort">
<ux-table-column type="checkbox" width="55"></ux-table-column> <ux-table-column type="checkbox" width="55"></ux-table-column>
<ux-table-column type="index" width="50" title=" "></ux-table-column> <ux-table-column type="index" width="50" title=" "></ux-table-column>
<ux-table-column v-for="(item,index) in resultItem.dataCols" :key="index" :prop="item.prop" :title="item.prop" <ux-table-column v-for="(item,index) in resultItem.dataCols" :key="index"
:prop="item.prop" :title="item.prop"
:width="item.width" sortable> :width="item.width" sortable>
<template slot="header" slot-scope="scope"> <template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="item.desc" placement="top"> <el-tooltip effect="dark" :content="item.desc" placement="top">
@@ -91,7 +98,8 @@
</el-tooltip> </el-tooltip>
</template> </template>
<template slot-scope="scope"> <template slot-scope="scope">
<textarea readonly :value="scope.row[item.prop]" class="el-textarea__inner" rows="1"></textarea> <textarea readonly :value="scope.row[item.prop]" class="el-textarea__inner"
rows="1"></textarea>
</template> </template>
</ux-table-column> </ux-table-column>
</ux-grid> </ux-grid>
@@ -139,14 +147,17 @@
</el-form-item> </el-form-item>
<el-form-item label="数据表:" v-if="downloadDataParam.downloadType === 'insert'"> <el-form-item label="数据表:" v-if="downloadDataParam.downloadType === 'insert'">
<el-checkbox :true-label="1" :false-label="0" v-model="downloadDataParam.dropTableFlag" <el-checkbox :true-label="1" :false-label="0" v-model="downloadDataParam.dropTableFlag"
@change="dropTableFlagChange">删除表{{ downloadDataParam.dropTableFlag == 1 ? '!!' : '' }} @change="dropTableFlagChange">删除表{{
downloadDataParam.dropTableFlag == 1 ? '!!' : ''
}}
</el-checkbox> </el-checkbox>
<el-checkbox :true-label="1" :false-label="0" v-model="downloadDataParam.createTableFlag" <el-checkbox :true-label="1" :false-label="0" v-model="downloadDataParam.createTableFlag"
@change="createTableFlagChange">创建表 @change="createTableFlagChange">创建表
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<el-form-item label="更新条件列:" v-if="downloadDataParam.downloadType === 'update'"> <el-form-item label="更新条件列:" v-if="downloadDataParam.downloadType === 'update'">
<el-select v-model="downloadDataParam.conditionColumnArr" multiple placeholder="不选则是没有条件的更新" <el-select v-model="downloadDataParam.conditionColumnArr" multiple
placeholder="不选则是没有条件的更新"
style="width: 370px;"> style="width: 370px;">
<el-option v-for="item in conditionDataCols" :key="item.prop" :label="item.prop" <el-option v-for="item in conditionDataCols" :key="item.prop" :label="item.prop"
:value="item.prop"></el-option> :value="item.prop"></el-option>
@@ -168,7 +179,8 @@
<el-row> <el-row>
<el-col :span="12">选择展示列</el-col> <el-col :span="12">选择展示列</el-col>
<el-col :span="12" style="text-align: right;"> <el-col :span="12" style="text-align: right;">
<el-checkbox v-model="choiceShowColumnAll" @change="choiceShowColumnAllChange">全选</el-checkbox> <el-checkbox v-model="choiceShowColumnAll" @change="choiceShowColumnAllChange">全选
</el-checkbox>
<el-button type="primary" size="mini" @click="choiceShowColumnOk" style="margin-left: 10px;">确定 <el-button type="primary" size="mini" @click="choiceShowColumnOk" style="margin-left: 10px;">确定
</el-button> </el-button>
</el-col> </el-col>
@@ -198,7 +210,7 @@ import Clickoutside from 'element-ui/src/utils/clickoutside'
export default { export default {
name: 'dataPreview', name: 'dataPreview',
directives: { Clickoutside }, directives: {Clickoutside},
data() { data() {
return { return {
executorDesc: "", executorDesc: "",
@@ -463,22 +475,22 @@ export default {
this.$set(this.choiceResultObj, this.executeShowTable, val); this.$set(this.choiceResultObj, this.executeShowTable, val);
}, },
//表格单元格鼠标焦点事件 //表格单元格鼠标焦点事件
mouseOnFocus(row, column, cell, event){ mouseOnFocus(row, column, cell, event) {
if(this.uxGridCell){ if (this.uxGridCell) {
this.uxGridCell.style.border = 'none' this.uxGridCell.style.border = 'none'
} }
cell.style.border = '2px solid #0078d7' cell.style.border = '2px solid #0078d7'
this.uxGridCell = cell; this.uxGridCell = cell;
}, },
//表格单元格 hover 退出 //表格单元格 hover 退出
mouseLeave(row, column, cell, event){ mouseLeave(row, column, cell, event) {
// if(this.uxGridCell){ // if(this.uxGridCell){
// this.uxGridCell.style.border = 'none' // this.uxGridCell.style.border = 'none'
// } // }
}, },
// 点击区域外 // 点击区域外
handleClickOutside() { handleClickOutside() {
if(this.uxGridCell){ if (this.uxGridCell) {
this.uxGridCell.style.border = 'none' this.uxGridCell.style.border = 'none'
} }
}, },
@@ -686,16 +698,18 @@ export default {
/deep/ .elx-table .elx-header--column.col--ellipsis { /deep/ .elx-table .elx-header--column.col--ellipsis {
height: 30px; height: 30px;
//padding-left: 5px; //padding-left: 5px;
} }
.xxpre{ .xxpre {
overflow: auto; overflow: auto;
} }
.el-textarea__inner{
.el-textarea__inner {
border: none; border: none;
background-color: #f0f8ff00; background-color: #f0f8ff00;
} }
.el-textarea__inner::-webkit-scrollbar { .el-textarea__inner::-webkit-scrollbar {
display: none; display: none;
} }

View File

@@ -2,7 +2,8 @@
<div class="data-executor-vue"> <div class="data-executor-vue">
<div style="padding: 0 10px 10px;height: 100%;box-sizing: border-box;"> <div style="padding: 0 10px 10px;height: 100%;box-sizing: border-box;">
<el-card style="margin-bottom: 5px;"> <el-card style="margin-bottom: 5px;">
<ace-editor v-model="sqlExecutorContent" ref="sqlEditor" @init="sqlExecutorInit" lang="sql" theme="monokai" <ace-editor v-model="sqlExecutorContent" ref="sqlEditor" @init="sqlExecutorInit" lang="sql"
theme="monokai"
width="100%" height="20" :options="sqlEditorConfig" :source="executorSource" width="100%" height="20" :options="sqlEditorConfig" :source="executorSource"
@cursorSelection="cursorSelection" style="margin-bottom: 5px;"></ace-editor> @cursorSelection="cursorSelection" style="margin-bottom: 5px;"></ace-editor>
<div> <div>
@@ -10,7 +11,8 @@
icon="el-icon-video-pause">取消执行 icon="el-icon-video-pause">取消执行
</el-button> </el-button>
<el-tooltip v-else effect="dark" content="Ctrl+R、Ctrl+Enter" placement="top"> <el-tooltip v-else effect="dark" content="Ctrl+R、Ctrl+Enter" placement="top">
<el-button v-on:click="doExecutorSql" type="primary" plain size="mini" icon="el-icon-video-play">{{executeButtonText}} <el-button v-on:click="doExecutorSql" type="primary" plain size="mini"
icon="el-icon-video-play">{{ executeButtonText }}
</el-button> </el-button>
</el-tooltip> </el-tooltip>
<el-button icon="el-icon-brush" size="mini" @click="formatterSql">SQL美化</el-button> <el-button icon="el-icon-brush" size="mini" @click="formatterSql">SQL美化</el-button>
@@ -29,7 +31,8 @@
</div> </div>
</div> </div>
<div v-if="sqlParams.length > 0" class="sql-params"> <div v-if="sqlParams.length > 0" class="sql-params">
<el-input :placeholder="'请输入'+param.key+'的值'" v-model="param.value" v-for="(param,index) in sqlParams" :key="index"> <el-input :placeholder="'请输入'+param.key+'的值'" v-model="param.value"
v-for="(param,index) in sqlParams" :key="index">
<template slot="prepend">{{ param.key }}</template> <template slot="prepend">{{ param.key }}</template>
</el-input> </el-input>
</div> </div>
@@ -62,7 +65,9 @@
</el-table-column> </el-table-column>
<el-table-column label="操作" width="160px"> <el-table-column label="操作" width="160px">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button size="mini" type="primary" @click="inputFavoriteSql(scope.row)">输入</el-button> <el-button size="mini" type="primary" @click="inputFavoriteSql(scope.row)">
输入
</el-button>
<el-button size="mini" type="success" @click="addFavorite(scope.row.content)" <el-button size="mini" type="success" @click="addFavorite(scope.row.content)"
style="margin-left: 10px;">收藏 style="margin-left: 10px;">收藏
</el-button> </el-button>
@@ -71,7 +76,8 @@
</el-table> </el-table>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="我的收藏" name="tabFavorite"> <el-tab-pane label="我的收藏" name="tabFavorite">
<el-table :data="myFavoriteList" stripe border style="width: 100%; margin-bottom: 5px;" v-infinite-scroll> <el-table :data="myFavoriteList" stripe border style="width: 100%; margin-bottom: 5px;"
v-infinite-scroll>
<el-table-column prop="createTime" label="执行时间" width="160px"></el-table-column> <el-table-column prop="createTime" label="执行时间" width="160px"></el-table-column>
<el-table-column prop="content" label="SQL"> <el-table-column prop="content" label="SQL">
<template slot-scope="scope"> <template slot-scope="scope">
@@ -81,8 +87,11 @@
</el-table-column> </el-table-column>
<el-table-column label="操作" width="160px"> <el-table-column label="操作" width="160px">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button size="mini" type="primary" v-on:click="inputFavoriteSql(scope.row)">输入</el-button> <el-button size="mini" type="primary" v-on:click="inputFavoriteSql(scope.row)">
<el-button size="mini" type="danger" v-on:click="delFavorite(scope.row)" style="margin-left: 10px;"> 输入
</el-button>
<el-button size="mini" type="danger" v-on:click="delFavorite(scope.row)"
style="margin-left: 10px;">
删除 删除
</el-button> </el-button>
</template> </template>
@@ -96,7 +105,8 @@
<div style="color: #f00;">{{ executeError }}</div> <div style="color: #f00;">{{ executeError }}</div>
</el-tab-pane> </el-tab-pane>
<template v-else> <template v-else>
<el-tab-pane :label="resultItem.label" :name="resultItem.name" v-for="(resultItem,index) in executeResultList" :key="index" <el-tab-pane :label="resultItem.label" :name="resultItem.name"
v-for="(resultItem,index) in executeResultList" :key="index"
lazy> lazy>
<div v-if="!!resultItem.errMsg" style="color: #f00;">{{ resultItem.errMsg }}</div> <div v-if="!!resultItem.errMsg" style="color: #f00;">{{ resultItem.errMsg }}</div>
<ux-grid v-else <ux-grid v-else
@@ -111,10 +121,17 @@
style="width: 100%; margin-bottom: 5px;" class="execute-result-table"> style="width: 100%; margin-bottom: 5px;" class="execute-result-table">
<ux-table-column type="checkbox" width="55"></ux-table-column> <ux-table-column type="checkbox" width="55"></ux-table-column>
<ux-table-column type="index" width="55" title=" "></ux-table-column> <ux-table-column type="index" width="55" title=" "></ux-table-column>
<ux-table-column v-for="(item,index) in resultItem.dataCols" :key="index" :prop="item.prop" :title="item.label" <ux-table-column v-for="(item,index) in resultItem.dataCols" :key="index"
:prop="item.prop" :title="item.label"
:width="item.width"> :width="item.width">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="item.desc" placement="top">
<span>{{ item.label }}</span>
</el-tooltip>
</template>
<template slot-scope="scope"> <template slot-scope="scope">
<textarea readonly :value="scope.row[item.prop]" class="el-textarea__inner" rows="1"></textarea> <textarea readonly :value="scope.row[item.prop]" class="el-textarea__inner"
rows="1"></textarea>
</template> </template>
</ux-table-column> </ux-table-column>
</ux-grid> </ux-grid>
@@ -130,8 +147,9 @@
<div v-if="resultItem.selectCount" style="position: absolute;right: 5px;bottom: 5px;"> <div v-if="resultItem.selectCount" style="position: absolute;right: 5px;bottom: 5px;">
<el-button type="primary" plain v-on:click="viewAllData()">查看所有</el-button> <el-button type="primary" plain v-on:click="viewAllData()">查看所有</el-button>
</div> </div>
<div v-if="!resultItem.selectCount" style="height: 20px;font-size: 13px;font-weight: 400;color: #606266;padding-left: 5px;"> <div v-if="!resultItem.selectCount"
{{resultItem.totalCount}} style="height: 20px;font-size: 13px;font-weight: 400;color: #606266;padding-left: 5px;">
{{ resultItem.totalCount }}
</div> </div>
</el-tab-pane> </el-tab-pane>
</template> </template>
@@ -173,7 +191,7 @@ import Clickoutside from 'element-ui/src/utils/clickoutside';
import merge from 'webpack-merge'; import merge from 'webpack-merge';
export default { export default {
directives: { Clickoutside }, directives: {Clickoutside},
data() { data() {
return { return {
//遮罩层 //遮罩层
@@ -243,7 +261,7 @@ export default {
this.height = 190; this.height = 190;
this.loadDatasourceList(); this.loadDatasourceList();
}, },
activated(){ activated() {
this.loadDatasourceList(); this.loadDatasourceList();
}, },
methods: { methods: {
@@ -275,10 +293,10 @@ export default {
} }
}); });
}, },
cursorSelection(sqlValue){ cursorSelection(sqlValue) {
if(sqlValue){ if (sqlValue) {
this.executeButtonText = '执行已选择的' this.executeButtonText = '执行已选择的'
}else{ } else {
this.executeButtonText = '执行' this.executeButtonText = '执行'
} }
}, },
@@ -365,7 +383,7 @@ export default {
this.$message.error("请先选择数据源"); this.$message.error("请先选择数据源");
return; return;
} }
if(!this.choiceDatabase){ if (!this.choiceDatabase) {
this.$message.error("请先选择数据库"); this.$message.error("请先选择数据库");
return; return;
} }
@@ -418,7 +436,7 @@ export default {
headerList.forEach(item => { headerList.forEach(item => {
let key = 'value_' + (headerIndex++); let key = 'value_' + (headerIndex++);
columnSet[key] = item; columnSet[key] = item;
previewColumns.push({prop: key, label: item}); previewColumns.push({prop: key, label: item, desc: item});
}); });
dataListTemp.forEach(item => { dataListTemp.forEach(item => {
let dataItem = {}, dataIndex = 0; let dataItem = {}, dataIndex = 0;
@@ -454,12 +472,12 @@ export default {
}); });
resIndex++; resIndex++;
//动态设置表格高度,尽量避免出现滚动条 //动态设置表格高度,尽量避免出现滚动条
if(result.selectCount){ if (result.selectCount) {
this.height = 170; this.height = 170;
} }
}); });
//多个结果情况下,且点击分页 //多个结果情况下,且点击分页
if(init!=1){ if (init != 1) {
this.executeShowTable = (resIndex === 1) ? "tabInfo" : "result_1"; this.executeShowTable = (resIndex === 1) ? "tabInfo" : "result_1";
} }
this.executeResultInfo = executeResultInfo; this.executeResultInfo = executeResultInfo;
@@ -468,7 +486,7 @@ export default {
}); });
}, },
//查看所有数据 //查看所有数据
viewAllData(init){ viewAllData(init) {
this.loadingAll = true; this.loadingAll = true;
if (!this.choiceDatasourceId) { if (!this.choiceDatasourceId) {
this.$message.error("请先选择数据源"); this.$message.error("请先选择数据源");
@@ -561,12 +579,12 @@ export default {
}); });
resIndex++; resIndex++;
//动态设置表格高度,尽量避免出现滚动条 //动态设置表格高度,尽量避免出现滚动条
if(result.selectCount){ if (result.selectCount) {
this.height = 170; this.height = 170;
} }
}); });
//多个结果情况下,且点击分页 //多个结果情况下,且点击分页
if(init!=1){ if (init != 1) {
this.executeShowTable = (resIndex === 1) ? "tabInfo" : "result_1"; this.executeShowTable = (resIndex === 1) ? "tabInfo" : "result_1";
} }
this.executeResultInfo = executeResultInfo; this.executeResultInfo = executeResultInfo;
@@ -594,11 +612,11 @@ export default {
if (this.datasourceList.length > 0) { if (this.datasourceList.length > 0) {
this.choiceDatasourceId = this.datasourceList[0].id; this.choiceDatasourceId = this.datasourceList[0].id;
//初次加载根据query值设置对应数据源 //初次加载根据query值设置对应数据源
if(this.$route.query.datasourceId){ if (this.$route.query.datasourceId) {
this.choiceDatasourceId = parseInt(this.$route.query.datasourceId); this.choiceDatasourceId = parseInt(this.$route.query.datasourceId);
} }
//初次加载根据query值设置对应数据库 //初次加载根据query值设置对应数据库
if(this.$route.query.database){ if (this.$route.query.database) {
this.choiceDatabase = this.$route.query.database; this.choiceDatabase = this.$route.query.database;
} }
this.executorSource = {sourceId: this.choiceDatasourceId}; this.executorSource = {sourceId: this.choiceDatasourceId};
@@ -617,9 +635,14 @@ export default {
let sysDbName = ["information_schema", "master", "model", "msdb", "tempdb"]; let sysDbName = ["information_schema", "master", "model", "msdb", "tempdb"];
let notSysDbItem = this.databaseList.find(item => sysDbName.indexOf(item.dbName) < 0); let notSysDbItem = this.databaseList.find(item => sysDbName.indexOf(item.dbName) < 0);
// 非初次加载动态改变url参数 // 非初次加载动态改变url参数
if(!initFlag){ if (!initFlag) {
this.choiceDatabase = (!!notSysDbItem) ? notSysDbItem.dbName : this.databaseList[0].dbName; this.choiceDatabase = (!!notSysDbItem) ? notSysDbItem.dbName : this.databaseList[0].dbName;
this.$router.replace({ query: { datasourceId: this.choiceDatasourceId,database:this.choiceDatabase } }) this.$router.replace({
query: {
datasourceId: this.choiceDatasourceId,
database: this.choiceDatabase
}
})
} }
this.executorSource = {sourceId: this.choiceDatasourceId, dbName: this.choiceDatabase}; this.executorSource = {sourceId: this.choiceDatasourceId, dbName: this.choiceDatabase};
} }
@@ -656,7 +679,7 @@ export default {
this.loadHistoryAndFavoriteList(); this.loadHistoryAndFavoriteList();
}, },
databaseChangeEvents() { databaseChangeEvents() {
this.$router.replace({ query: { datasourceId: this.choiceDatasourceId,database:this.choiceDatabase } }) this.$router.replace({query: {datasourceId: this.choiceDatasourceId, database: this.choiceDatabase}})
this.executorSource = {sourceId: this.choiceDatasourceId, dbName: this.choiceDatabase}; this.executorSource = {sourceId: this.choiceDatasourceId, dbName: this.choiceDatabase};
this.currentPage = 1; this.currentPage = 1;
}, },
@@ -698,7 +721,7 @@ export default {
handleSelectionChange(val) { handleSelectionChange(val) {
this.$set(this.choiceResultObj, this.executeShowTable, val); this.$set(this.choiceResultObj, this.executeShowTable, val);
}, },
tabHandleClick(t){ tabHandleClick(t) {
}, },
doCopyCheckLineUpdate() { doCopyCheckLineUpdate() {
@@ -732,22 +755,22 @@ export default {
} }
}, },
//表格单元格鼠标焦点事件 //表格单元格鼠标焦点事件
mouseOnFocus(row, column, cell, event){ mouseOnFocus(row, column, cell, event) {
if(this.uxGridCell){ if (this.uxGridCell) {
this.uxGridCell.style.border = 'none' this.uxGridCell.style.border = 'none'
} }
cell.style.border = '2px solid #0078d7' cell.style.border = '2px solid #0078d7'
this.uxGridCell = cell; this.uxGridCell = cell;
}, },
//表格单元格 hover 退出 //表格单元格 hover 退出
mouseLeave(row, column, cell, event){ mouseLeave(row, column, cell, event) {
// if(this.uxGridCell){ // if(this.uxGridCell){
// this.uxGridCell.style.border = 'none' // this.uxGridCell.style.border = 'none'
// } // }
}, },
// 点击区域外 // 点击区域外
handleClickOutside() { handleClickOutside() {
if(this.uxGridCell){ if (this.uxGridCell) {
this.uxGridCell.style.border = 'none' this.uxGridCell.style.border = 'none'
} }
}, },
@@ -837,25 +860,30 @@ export default {
/deep/ .elx-table .elx-header--column.col--ellipsis { /deep/ .elx-table .elx-header--column.col--ellipsis {
height: 30px; height: 30px;
//padding-left: 5px; //padding-left: 5px;
} }
.el-textarea__inner{
.el-textarea__inner {
border: none; border: none;
background-color: #f0f8ff00; background-color: #f0f8ff00;
} }
.el-textarea__inner::-webkit-scrollbar { .el-textarea__inner::-webkit-scrollbar {
display: none; display: none;
} }
/deep/ .el-tabs--border-card>.el-tabs__content {
/deep/ .el-tabs--border-card > .el-tabs__content {
padding: 5px; padding: 5px;
} }
/deep/ .elx-table .elx-body--column.col--ellipsis>.elx-cell,
.elx-table .elx-footer--column.col--ellipsis>.elx-cell, /deep/ .elx-table .elx-body--column.col--ellipsis > .elx-cell,
.elx-table .elx-header--column.col--ellipsis>.elx-cell{ .elx-table .elx-footer--column.col--ellipsis > .elx-cell,
.elx-table .elx-header--column.col--ellipsis > .elx-cell {
overflow: auto; overflow: auto;
text-overflow: unset; text-overflow: unset;
} }
/deep/ .elx-table .elx-body--column.col--ellipsis>.elx-cell::-webkit-scrollbar {
/deep/ .elx-table .elx-body--column.col--ellipsis > .elx-cell::-webkit-scrollbar {
display: none; display: none;
} }
</style> </style>