feat: dbms表数据列表新增排序

This commit is contained in:
meilin.huang
2022-01-17 17:10:38 +08:00
parent cf6045b4c6
commit 33377a08e6

View File

@@ -18,7 +18,6 @@
<el-form-item>
<el-button
type="success"
size="mini"
@click="
newQueryShow = true;
activeName = 'second';
@@ -32,9 +31,9 @@
</el-row>
</div>
<el-container style="border: 1px solid #eee; margin-top: 1px; height: 600px">
<el-container style="border: 1px solid #eee; margin-top: 1px; height: 630px">
<el-container style="margin-left: 2px">
<el-header style="text-align: left; height: 45px; font-size: 12px; padding: 0px">
<el-header style="text-align: left; height: 35px; font-size: 12px; padding: 0px">
<el-select v-model="tableName" placeholder="请选择表" @change="changeTable" filterable style="width: 99%">
<el-option
v-for="item in tableMetadata"
@@ -47,21 +46,22 @@
</el-header>
<el-main style="padding: 0px; overflow: hidden">
<el-table :data="columnMetadata" height="100%" size="mini">
<el-table :data="columnMetadata" height="100%" size="small">
<el-table-column prop="columnName" label="名称" show-overflow-tooltip> </el-table-column>
<el-table-column prop="columnComment" label="备注" show-overflow-tooltip> </el-table-column>
<el-table-column width="120" prop="columnType" label="类型" show-overflow-tooltip> </el-table-column>
</el-table>
</el-main>
</el-container>
<el-tabs style="width: 70%; margin-left: 20px" v-model="activeName" @tab-click="handleClick">
<el-tabs style="width: 70%; margin-left: 10px" v-model="activeName">
<el-tab-pane label="数据信息" name="first">
<el-table
@cell-dblclick="cellClick"
@sort-change="tableSortChange"
style="margin-top: 1px"
:data="execRes.data"
size="mini"
max-height="500"
size="small"
max-height="580"
:empty-text="execRes.emptyResText"
stripe
border
@@ -75,19 +75,16 @@
:prop="item"
:label="item"
show-overflow-tooltip
:sortable="nowTableName != '' ? 'custom' : false"
>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="新建查询" v-if="newQueryShow" name="second">
<el-aside id="sqlcontent" width="75%" style="background-color: rgb(238, 241, 246)">
<el-aside id="sqlcontent" width="100%" style="background-color: rgb(238, 241, 246)">
<div class="toolbar">
<div class="fl">
<!-- <el-button v-waves @click="runSql" type="success" icon="video-play" plain>执行</el-button>
<el-button v-waves @click="formatSql" type="primary" icon="magic-stick" plain>格式化</el-button> -->
<el-upload
style="display: inline-block; margin-left: 10px"
:before-upload="beforeUpload"
@@ -102,7 +99,7 @@
multiple
:limit="100"
>
<el-button v-waves type="success" icon="video-play" plain>sql脚本执行</el-button>
<el-button type="success" icon="video-play" plain size="small">sql脚本执行</el-button>
</el-upload>
</div>
@@ -121,8 +118,8 @@
</el-option>
</el-select>
<el-button v-waves @click="saveSql" type="primary" icon="document-add" plain>保存</el-button>
<el-button v-waves @click="deleteSql" type="danger" icon="delete" plain>删除</el-button>
<el-button @click="saveSql" type="primary" icon="document-add" plain size="small">保存</el-button>
<el-button @click="deleteSql" type="danger" icon="delete" plain size="small">删除</el-button>
</div>
</div>
<codemirror
@@ -135,8 +132,8 @@
:options="cmOptions"
/>
<el-button-group :style="btnStyle">
<el-button v-waves @click="runSql" type="success" icon="video-play" size="small" plain>执行</el-button>
<el-button v-waves @click="formatSql" type="primary" icon="magic-stick" size="small" plain>格式化</el-button>
<el-button @click="runSql" type="success" icon="video-play" size="small" plain>执行</el-button>
<el-button @click="formatSql" type="primary" icon="magic-stick" size="small" plain>格式化</el-button>
</el-button-group>
</el-aside>
</el-tab-pane>
@@ -150,7 +147,7 @@
</template>
<script lang="ts">
import { toRefs, reactive, computed, defineComponent, ref } from 'vue';
import { h, toRefs, reactive, computed, defineComponent, ref } from 'vue';
import { dbApi } from './api';
import _ from 'lodash';
@@ -166,7 +163,7 @@ import { codemirror } from '@/components/codemirror';
import 'codemirror/addon/hint/show-hint.js';
import 'codemirror/addon/hint/sql-hint.js';
import sqlFormatter from 'sql-formatter';
import { format as sqlFormatter } from 'sql-formatter';
import { notNull, notEmpty } from '@/common/assert';
import { ElMessage, ElMessageBox } from 'element-plus';
import ProjectEnvSelect from '../component/ProjectEnvSelect.vue';
@@ -185,10 +182,12 @@ export default defineComponent({
const state = reactive({
token: token,
defalutLimit: 25, // 默认查询数量
dbs: [],
tables: [],
dbId: null,
tableName: '',
nowTableName: '', // 当前表格数据操作的数据库表名,用于双击编辑表内容使用
tableMetadata: [],
columnMetadata: [],
sqlName: '',
@@ -283,20 +282,39 @@ export default defineComponent({
/**
* 执行sql str
*
* @param sql 执行的sql
* @param replaceColumn 是否替换列名如点击排序时不需要替换表头否则排序icon无法回显
*/
const runSqlStr = async (sql: string) => {
state.execRes.tableColumn = [];
const runSqlStr = async (sql: string, replaceColumn: boolean = true) => {
state.activeName = 'first';
sql = sql.trim();
if (replaceColumn) {
state.execRes.tableColumn = [];
}
state.execRes.data = [];
state.execRes.emptyResText = '查询中...';
console.log(sql);
const res = await dbApi.sqlExec.request({
id: state.dbId,
sql: sql,
});
state.execRes.emptyResText = '没有数据';
state.execRes.tableColumn = res.colNames;
if (replaceColumn) {
state.execRes.tableColumn = res.colNames;
}
state.execRes.data = res.res;
state.activeName = 'first';
// 设置当前可双击修改表数据内容的表名即只有以该字符串开头的sql才可修改表数据内容
if (sql.startsWith('SELECT *') || sql.startsWith('select *')) {
const tableName = sql.split(/from/i)[1];
if (tableName) {
state.nowTableName = tableName.trim().split(' ')[0];
} else {
state.nowTableName = '';
}
} else {
state.nowTableName = '';
}
};
const beforeUpload = (file: File) => {
@@ -423,6 +441,9 @@ export default defineComponent({
getUserSql();
};
/**
* 获取用户保存的sql模板内容
*/
const getUserSql = () => {
notNull(state.dbId, '请先选择数据库');
dbApi.getSql.request({ id: state.dbId, type: 1, name: state.sqlName }).then((res) => {
@@ -434,6 +455,9 @@ export default defineComponent({
});
};
/**
* 获取用户保存的sql模板名称
*/
const getSqlNames = () => {
dbApi.getSqlNames
.request({
@@ -508,34 +532,108 @@ export default defineComponent({
});
if (execSelectSql) {
runSqlStr(`SELECT * FROM ${tableName} ORDER BY create_time DESC LIMIT 25`);
runSqlStr(`SELECT * FROM ${tableName} LIMIT ${state.defalutLimit}`);
}
};
// 监听单元格点击事件
const cellClick = (row: any, column: any, cell: any, event: any) => {
console.log(cell.children[0].tagName);
// 如果当前操作的表名不存在,则不允许修改表格内容
if (!state.nowTableName) {
return;
}
let isDiv = cell.children[0].tagName === 'DIV';
let text = cell.children[0].innerText;
let div = cell.children[0];
if (isDiv) {
let input = document.createElement('input');
input.setAttribute('value', text);
input.setAttribute('style', 'height:30px');
// 将表格width也赋值于输入框避免输入框长度超过表格长度
input.setAttribute('style', 'height:30px;' + div.getAttribute('style'));
cell.replaceChildren(input);
input.focus();
input.addEventListener('blur', () => {
div.innerText = input.value;
cell.replaceChildren(div);
console.log(input.value, column.rawColumnKey, text, 42242);
if (input.value !== text) {
dbApi.sqlExec.request({
id: state.dbId,
sql: `UPDATE ${state.tableName} SET ${column.rawColumnKey} = '${input.value}' WHERE ${column.rawColumnKey} = '${text}'`,
const primaryKey = getTablePrimaryKeyColume(state.nowTableName);
const sql = `UPDATE ${state.nowTableName} SET ${column.rawColumnKey} = '${input.value}' WHERE ${primaryKey} = '${row[primaryKey]}'`;
promptExeSql(sql, () => {
div.innerText = text;
});
}
});
}
};
/**
* 获取表主键列名,目前先以默认表字段第一个字段
*/
const getTablePrimaryKeyColume = (tableName: string) => {
// 'id [bigint(20) unsigned]'
return state.cmOptions.hintOptions.tables[tableName][0].split(' ')[0];
};
/**
* 弹框提示是否执行sql
*/
const promptExeSql = (sql: string, cancelFunc: any = null) => {
ElMessageBox({
title: '执行SQL',
message: h(
'div',
{
attrs: {
class: 'el-textarea',
},
},
[
h('textarea', {
attrs: {
class: 'el-textarea__inner',
autocomplete: 'off',
rows: 8,
},
style: {
height: '150px',
width: '100%',
fontWeight: '600',
},
value: sqlFormatter(sql),
}),
]
),
showCancelButton: true,
confirmButtonText: '执行',
cancelButtonText: '取消',
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
instance.confirmButtonLoading = true;
instance.confirmButtonText = '执行中...';
setTimeout(() => {
done();
setTimeout(() => {
instance.confirmButtonLoading = false;
}, 200);
}, 200);
} else {
done();
}
},
})
.then((action) => {
dbApi.sqlExec.request({
id: state.dbId,
sql: sql,
});
})
.catch(() => {
if (cancelFunc) {
cancelFunc();
}
});
};
// 添加新数据行
// const addRow = () => {
// let obj: any = {};
@@ -564,10 +662,10 @@ export default defineComponent({
let selectSql = codemirror.value.getSelection();
// 有选中sql则只格式化选中部分否则格式化全部
if (selectSql != '') {
codemirror.value.replaceSelection(sqlFormatter.format(selectSql));
codemirror.value.replaceSelection(sqlFormatter(selectSql));
} else {
/* 将sql内容进行格式后放入编辑器中*/
state.sql = sqlFormatter.format(sqlFormatter.format(state.sql));
state.sql = sqlFormatter(state.sql);
}
};
@@ -575,10 +673,11 @@ export default defineComponent({
const res = await dbApi.dbs.request(state.params);
state.dbs = res.list;
};
/**
* 获取选择文字,显示隐藏按钮,防抖
*/
const getSelection = _.debounce((e) => {
const getSelection = _.debounce((e: any) => {
let temp = codemirror.value.getSelection();
if (temp) {
state.btnStyle.display = 'block';
@@ -592,9 +691,22 @@ export default defineComponent({
state.btnStyle.top = '';
}
}, 100);
const listenMouse = (e: any) => {
getSelection(e);
};
/**
* 表排序字段变更
*/
const tableSortChange = (sort: any) => {
if (!state.nowTableName) {
return;
}
const sortType = sort.order == 'descending' ? 'DESC' : 'ASC';
runSqlStr(`SELECT * FROM ${state.nowTableName} ORDER BY ${sort.prop} ${sortType} LIMIT ${state.defalutLimit}`, false);
};
return {
...toRefs(state),
cmEditor,
@@ -615,6 +727,7 @@ export default defineComponent({
formatSql,
onBeforeChange,
listenMouse,
tableSortChange,
};
},
});