2021-06-07 17:22:07 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="toolbar">
|
2021-07-28 18:03:19 +08:00
|
|
|
|
<el-row type="flex" justify="space-between">
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<project-env-select @changeProjectEnv="changeProjectEnv" @clear="clearDb">
|
|
|
|
|
|
<template #default>
|
|
|
|
|
|
<el-form-item label="数据库">
|
|
|
|
|
|
<el-select v-model="dbId" placeholder="请选择数据库" @change="changeDb" @clear="clearDb" clearable filterable>
|
|
|
|
|
|
<el-option v-for="item in dbs" :key="item.id" :label="item.database" :value="item.id">
|
|
|
|
|
|
<span style="float: left">{{ item.database }}</span>
|
|
|
|
|
|
<span style="float: right; color: #8492a6; margin-left: 6px; font-size: 13px">{{
|
|
|
|
|
|
`${item.name} [${item.type}]`
|
|
|
|
|
|
}}</span>
|
|
|
|
|
|
</el-option>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</project-env-select>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
2021-06-07 17:22:07 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2022-01-19 15:10:17 +08:00
|
|
|
|
<el-container style="border: 1px solid #eee; margin-top: 1px; height: 640px">
|
2022-01-16 05:19:44 +08:00
|
|
|
|
<el-container style="margin-left: 2px">
|
2022-01-17 17:10:38 +08:00
|
|
|
|
<el-header style="text-align: left; height: 35px; font-size: 12px; padding: 0px">
|
2022-01-16 05:19:44 +08:00
|
|
|
|
<el-select v-model="tableName" placeholder="请选择表" @change="changeTable" filterable style="width: 99%">
|
|
|
|
|
|
<el-option
|
|
|
|
|
|
v-for="item in tableMetadata"
|
|
|
|
|
|
:key="item.tableName"
|
|
|
|
|
|
:label="item.tableName + (item.tableComment != '' ? `【${item.tableComment}】` : '')"
|
|
|
|
|
|
:value="item.tableName"
|
|
|
|
|
|
>
|
|
|
|
|
|
</el-option>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-header>
|
|
|
|
|
|
|
|
|
|
|
|
<el-main style="padding: 0px; overflow: hidden">
|
2022-01-17 17:10:38 +08:00
|
|
|
|
<el-table :data="columnMetadata" height="100%" size="small">
|
2022-01-16 05:19:44 +08:00
|
|
|
|
<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>
|
2022-01-19 15:10:17 +08:00
|
|
|
|
|
|
|
|
|
|
<el-tabs @tab-remove="removeDataTab" @tab-click="onDataTabClick" style="width: 70%; margin-left: 10px" v-model="activeName">
|
2022-01-20 18:01:11 +08:00
|
|
|
|
<el-tab-pane :label="queryTab.label" :name="queryTab.name">
|
2022-01-19 15:10:17 +08:00
|
|
|
|
<div>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="toolbar">
|
|
|
|
|
|
<div class="fl">
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
style="display: inline-block; margin-left: 10px"
|
|
|
|
|
|
:before-upload="beforeUpload"
|
|
|
|
|
|
:on-success="execSqlFileSuccess"
|
|
|
|
|
|
:headers="{ Authorization: token }"
|
|
|
|
|
|
:data="{
|
|
|
|
|
|
dbId: 1,
|
|
|
|
|
|
}"
|
|
|
|
|
|
:action="getUploadSqlFileUrl()"
|
|
|
|
|
|
:show-file-list="false"
|
|
|
|
|
|
name="file"
|
|
|
|
|
|
multiple
|
|
|
|
|
|
:limit="100"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-button type="success" icon="video-play" plain size="small">sql脚本执行</el-button>
|
|
|
|
|
|
</el-upload>
|
2022-01-20 18:01:11 +08:00
|
|
|
|
<el-button @click="onCommit" class="ml5" type="success" icon="CircleCheck" plain size="small">commit</el-button>
|
2022-01-19 15:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div style="float: right" class="fl">
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
v-model="sqlName"
|
|
|
|
|
|
placeholder="选择or输入SQL模板名"
|
|
|
|
|
|
@change="changeSqlTemplate"
|
|
|
|
|
|
filterable
|
|
|
|
|
|
allow-create
|
|
|
|
|
|
default-first-option
|
|
|
|
|
|
class="mr10"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-option v-for="item in sqlNames" :key="item" :label="item.database" :value="item">
|
|
|
|
|
|
{{ item }}
|
|
|
|
|
|
</el-option>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
|
|
|
|
|
|
<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>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mt10">
|
|
|
|
|
|
<codemirror
|
|
|
|
|
|
@mousemove="listenMouse"
|
|
|
|
|
|
@beforeChange="onBeforeChange"
|
|
|
|
|
|
height="300px"
|
|
|
|
|
|
class="codesql"
|
|
|
|
|
|
ref="cmEditor"
|
|
|
|
|
|
language="sql"
|
|
|
|
|
|
v-model="sql"
|
|
|
|
|
|
:options="cmOptions"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button-group :style="btnStyle">
|
|
|
|
|
|
<el-button @click="onRunSql" 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>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mt10">
|
2022-01-20 18:01:11 +08:00
|
|
|
|
<el-row v-if="queryTab.nowTableName">
|
|
|
|
|
|
<el-link @click="onDeleteData" class="ml5" type="danger" icon="delete" :underline="false"></el-link>
|
|
|
|
|
|
</el-row>
|
2022-01-19 15:10:17 +08:00
|
|
|
|
<el-table
|
|
|
|
|
|
@cell-dblclick="cellClick"
|
2022-01-20 18:01:11 +08:00
|
|
|
|
@selection-change="onDataSelectionChange"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
style="margin-top: 1px"
|
2022-01-20 18:01:11 +08:00
|
|
|
|
:data="queryTab.execRes.data"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
size="small"
|
|
|
|
|
|
max-height="220"
|
|
|
|
|
|
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改"
|
|
|
|
|
|
stripe
|
|
|
|
|
|
border
|
|
|
|
|
|
>
|
2022-01-20 18:01:11 +08:00
|
|
|
|
<el-table-column
|
|
|
|
|
|
v-if="queryTab.execRes.tableColumn.length > 0 && queryTab.nowTableName"
|
|
|
|
|
|
type="selection"
|
|
|
|
|
|
width="35"
|
|
|
|
|
|
/>
|
2022-01-19 15:10:17 +08:00
|
|
|
|
<el-table-column
|
|
|
|
|
|
min-width="100"
|
2022-01-20 18:01:11 +08:00
|
|
|
|
:width="flexColumnWidth(item, queryTab.execRes.data)"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
align="center"
|
2022-01-20 18:01:11 +08:00
|
|
|
|
v-for="item in queryTab.execRes.tableColumn"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
:key="item"
|
|
|
|
|
|
:prop="item"
|
|
|
|
|
|
:label="item"
|
|
|
|
|
|
show-overflow-tooltip
|
|
|
|
|
|
>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
|
|
|
|
<el-tab-pane closable v-for="dt in dataTabs" :key="dt.name" :label="dt.label" :name="dt.name">
|
2022-01-20 18:01:11 +08:00
|
|
|
|
<el-row v-if="dbId">
|
|
|
|
|
|
<el-link @click="onRefresh(dt.name)" icon="refresh" :underline="false"></el-link>
|
|
|
|
|
|
<el-link @click="addRow" class="ml5" type="primary" icon="plus" :underline="false"></el-link>
|
|
|
|
|
|
<el-link @click="onDeleteData" class="ml5" type="danger" icon="delete" :underline="false"></el-link>
|
|
|
|
|
|
|
|
|
|
|
|
<el-tooltip class="box-item" effect="dark" content="commit" placement="top">
|
|
|
|
|
|
<el-link @click="onCommit" class="ml5" type="success" icon="check" :underline="false"></el-link>
|
|
|
|
|
|
</el-tooltip>
|
|
|
|
|
|
</el-row>
|
2022-01-16 19:40:20 +08:00
|
|
|
|
<el-table
|
|
|
|
|
|
@cell-dblclick="cellClick"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
@sort-change="onTableSortChange"
|
2022-01-20 18:01:11 +08:00
|
|
|
|
@selection-change="onDataSelectionChange"
|
2022-01-16 19:40:20 +08:00
|
|
|
|
style="margin-top: 1px"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
:data="dt.execRes.data"
|
2022-01-17 17:10:38 +08:00
|
|
|
|
size="small"
|
|
|
|
|
|
max-height="580"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
:empty-text="dt.execRes.emptyResText"
|
2022-01-16 19:40:20 +08:00
|
|
|
|
stripe
|
|
|
|
|
|
border
|
|
|
|
|
|
>
|
2022-01-20 18:01:11 +08:00
|
|
|
|
<el-table-column v-if="dt.execRes.tableColumn.length > 0" type="selection" width="35" />
|
2022-01-16 19:40:20 +08:00
|
|
|
|
<el-table-column
|
|
|
|
|
|
min-width="100"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
:width="flexColumnWidth(item, dt.execRes.data)"
|
2022-01-16 19:40:20 +08:00
|
|
|
|
align="center"
|
2022-01-19 15:10:17 +08:00
|
|
|
|
v-for="item in dt.execRes.tableColumn"
|
2022-01-16 19:40:20 +08:00
|
|
|
|
:key="item"
|
|
|
|
|
|
:prop="item"
|
|
|
|
|
|
:label="item"
|
|
|
|
|
|
show-overflow-tooltip
|
2022-01-17 17:10:38 +08:00
|
|
|
|
:sortable="nowTableName != '' ? 'custom' : false"
|
2022-01-16 19:40:20 +08:00
|
|
|
|
>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
</el-tabs>
|
2021-06-07 17:22:07 +08:00
|
|
|
|
</el-container>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script lang="ts">
|
2022-01-20 18:01:11 +08:00
|
|
|
|
import { h, toRefs, reactive, computed, defineComponent, ref } from 'vue';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
import { dbApi } from './api';
|
2021-12-25 00:58:07 +08:00
|
|
|
|
import _ from 'lodash';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
|
|
|
|
|
|
import 'codemirror/addon/hint/show-hint.css';
|
|
|
|
|
|
// import base style
|
|
|
|
|
|
import 'codemirror/lib/codemirror.css';
|
|
|
|
|
|
// 引入主题后还需要在 options 中指定主题才会生效
|
|
|
|
|
|
import 'codemirror/theme/base16-light.css';
|
|
|
|
|
|
|
|
|
|
|
|
import 'codemirror/addon/selection/active-line';
|
|
|
|
|
|
import { codemirror } from '@/components/codemirror';
|
|
|
|
|
|
// import 'codemirror/mode/sql/sql.js';
|
2021-07-28 18:03:19 +08:00
|
|
|
|
import 'codemirror/addon/hint/show-hint.js';
|
|
|
|
|
|
import 'codemirror/addon/hint/sql-hint.js';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
|
2022-01-17 17:10:38 +08:00
|
|
|
|
import { format as sqlFormatter } from 'sql-formatter';
|
2022-01-20 18:01:11 +08:00
|
|
|
|
import { notNull, notEmpty, isTrue } from '@/common/assert';
|
|
|
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
2021-07-28 18:03:19 +08:00
|
|
|
|
import ProjectEnvSelect from '../component/ProjectEnvSelect.vue';
|
2021-11-25 14:34:15 +08:00
|
|
|
|
import config from '@/common/config';
|
|
|
|
|
|
import { getSession } from '@/common/utils/storage';
|
2022-01-20 18:01:11 +08:00
|
|
|
|
import { key } from '../../../store/index';
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
export default defineComponent({
|
2021-07-28 18:03:19 +08:00
|
|
|
|
name: 'SqlExec',
|
2021-06-07 17:22:07 +08:00
|
|
|
|
components: {
|
|
|
|
|
|
codemirror,
|
2021-07-28 18:03:19 +08:00
|
|
|
|
ProjectEnvSelect,
|
2021-06-07 17:22:07 +08:00
|
|
|
|
},
|
|
|
|
|
|
setup() {
|
|
|
|
|
|
const cmEditor: any = ref(null);
|
2021-11-25 14:34:15 +08:00
|
|
|
|
const token = getSession('token');
|
|
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
const state = reactive({
|
2021-11-25 14:34:15 +08:00
|
|
|
|
token: token,
|
2022-01-17 17:10:38 +08:00
|
|
|
|
defalutLimit: 25, // 默认查询数量
|
2021-06-07 17:22:07 +08:00
|
|
|
|
dbs: [],
|
|
|
|
|
|
tables: [],
|
2021-07-28 18:03:19 +08:00
|
|
|
|
dbId: null,
|
2021-06-07 17:22:07 +08:00
|
|
|
|
tableName: '',
|
|
|
|
|
|
tableMetadata: [],
|
|
|
|
|
|
columnMetadata: [],
|
2022-01-19 15:10:17 +08:00
|
|
|
|
sqlName: '', // 当前sql模板名
|
|
|
|
|
|
sqlNames: [], // 所有sql模板名
|
2021-06-07 17:22:07 +08:00
|
|
|
|
sql: '',
|
2022-01-19 15:10:17 +08:00
|
|
|
|
activeName: 'Query',
|
|
|
|
|
|
queryTabName: 'Query',
|
2022-01-20 18:01:11 +08:00
|
|
|
|
nowTableName: '', // 当前表格数据操作的数据库表名,用于双击编辑表内容使用
|
2022-01-19 15:10:17 +08:00
|
|
|
|
dataTabs: {}, // 点击表信息后执行结果数据展示tabs
|
2022-01-20 18:01:11 +08:00
|
|
|
|
// 查询tab
|
|
|
|
|
|
queryTab: {
|
|
|
|
|
|
label: '查询',
|
|
|
|
|
|
name: 'Query',
|
|
|
|
|
|
// 点击执行按钮执行结果信息
|
|
|
|
|
|
execRes: {
|
|
|
|
|
|
data: [],
|
|
|
|
|
|
tableColumn: [],
|
|
|
|
|
|
},
|
|
|
|
|
|
nowTableName: '', //当前表格数据操作的数据库表名,用于双击编辑表内容使用
|
|
|
|
|
|
selectionDatas: [],
|
2021-06-07 17:22:07 +08:00
|
|
|
|
},
|
|
|
|
|
|
params: {
|
|
|
|
|
|
pageNum: 1,
|
|
|
|
|
|
pageSize: 10,
|
2021-07-28 18:03:19 +08:00
|
|
|
|
envId: null,
|
2021-06-07 17:22:07 +08:00
|
|
|
|
},
|
2021-12-25 00:58:07 +08:00
|
|
|
|
btnStyle: {
|
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
|
zIndex: 1000,
|
|
|
|
|
|
display: 'none',
|
|
|
|
|
|
left: '',
|
|
|
|
|
|
top: '',
|
|
|
|
|
|
},
|
2021-06-07 17:22:07 +08:00
|
|
|
|
cmOptions: {
|
|
|
|
|
|
tabSize: 4,
|
|
|
|
|
|
mode: 'text/x-sql',
|
|
|
|
|
|
lineNumbers: true,
|
|
|
|
|
|
line: true,
|
|
|
|
|
|
indentWithTabs: true,
|
|
|
|
|
|
smartIndent: true,
|
2021-07-28 18:03:19 +08:00
|
|
|
|
matchBrackets: true,
|
2021-06-07 17:22:07 +08:00
|
|
|
|
theme: 'base16-light',
|
|
|
|
|
|
autofocus: true,
|
|
|
|
|
|
extraKeys: { Tab: 'autocomplete' }, // 自定义快捷键
|
|
|
|
|
|
hintOptions: {
|
|
|
|
|
|
completeSingle: false,
|
|
|
|
|
|
// 自定义提示选项
|
|
|
|
|
|
tables: {},
|
|
|
|
|
|
},
|
|
|
|
|
|
// more CodeMirror options...
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2022-01-20 18:01:11 +08:00
|
|
|
|
const tableMap = new Map();
|
|
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
const codemirror: any = computed(() => {
|
|
|
|
|
|
return cmEditor.value.coder;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 项目及环境更改后的回调事件
|
|
|
|
|
|
*/
|
|
|
|
|
|
const changeProjectEnv = (projectId: any, envId: any) => {
|
|
|
|
|
|
state.dbs = [];
|
|
|
|
|
|
state.dbId = null;
|
|
|
|
|
|
clearDb();
|
|
|
|
|
|
if (envId != null) {
|
|
|
|
|
|
state.params.envId = envId;
|
|
|
|
|
|
search();
|
|
|
|
|
|
}
|
2021-06-07 17:22:07 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 输入字符给提示
|
|
|
|
|
|
*/
|
|
|
|
|
|
const inputRead = (instance: any, changeObj: any) => {
|
|
|
|
|
|
if (/^[a-zA-Z]/.test(changeObj.text[0])) {
|
|
|
|
|
|
showHint();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
const onBeforeChange = (instance: any, changeObj: any) => {
|
|
|
|
|
|
var text = changeObj.text[0];
|
|
|
|
|
|
// 将sql提示去除
|
|
|
|
|
|
changeObj.text[0] = text.split(' ')[0];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 执行sql
|
|
|
|
|
|
*/
|
2022-01-19 15:10:17 +08:00
|
|
|
|
const onRunSql = async () => {
|
2021-07-28 18:03:19 +08:00
|
|
|
|
notNull(state.dbId, '请先选择数据库');
|
2021-06-07 17:22:07 +08:00
|
|
|
|
// 没有选中的文本,则为全部文本
|
2021-07-28 18:03:19 +08:00
|
|
|
|
let sql = getSql();
|
|
|
|
|
|
notNull(sql, '内容不能为空');
|
2022-01-19 15:10:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 即只有以该字符串开头的sql才可修改表数据内容
|
|
|
|
|
|
if (sql.startsWith('SELECT *') || sql.startsWith('select *') || sql.startsWith('SELECT\n *')) {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
state.queryTab.selectionDatas = [];
|
2022-01-19 15:10:17 +08:00
|
|
|
|
const tableName = sql.split(/from/i)[1];
|
|
|
|
|
|
if (tableName) {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
const tn = tableName.trim().split(' ')[0];
|
|
|
|
|
|
state.queryTab.nowTableName = tn;
|
|
|
|
|
|
state.nowTableName = tn;
|
2022-01-19 15:10:17 +08:00
|
|
|
|
} else {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
state.queryTab.nowTableName = '';
|
2022-01-19 15:10:17 +08:00
|
|
|
|
state.nowTableName = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
state.queryTab.nowTableName = '';
|
2022-01-19 15:10:17 +08:00
|
|
|
|
state.nowTableName = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const colAndData: any = await runSql(sql);
|
2022-01-20 18:01:11 +08:00
|
|
|
|
state.queryTab.execRes.data = colAndData.res;
|
|
|
|
|
|
state.queryTab.execRes.tableColumn = colAndData.colNames;
|
2021-12-02 10:35:48 +08:00
|
|
|
|
};
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
2021-12-02 10:35:48 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 执行sql str
|
2022-01-17 17:10:38 +08:00
|
|
|
|
*
|
|
|
|
|
|
* @param sql 执行的sql
|
2021-12-02 10:35:48 +08:00
|
|
|
|
*/
|
2022-01-19 15:10:17 +08:00
|
|
|
|
const runSql = (sql: string) => {
|
|
|
|
|
|
return dbApi.sqlExec.request({
|
2021-06-07 17:22:07 +08:00
|
|
|
|
id: state.dbId,
|
2022-01-19 15:10:17 +08:00
|
|
|
|
sql: sql.trim(),
|
2021-06-07 17:22:07 +08:00
|
|
|
|
});
|
2022-01-19 15:10:17 +08:00
|
|
|
|
};
|
2022-01-17 17:10:38 +08:00
|
|
|
|
|
2022-01-19 15:10:17 +08:00
|
|
|
|
const removeDataTab = (targetName: string) => {
|
|
|
|
|
|
const tabNames = Object.keys(state.dataTabs);
|
|
|
|
|
|
let activeName = state.activeName;
|
|
|
|
|
|
tabNames.forEach((name, index) => {
|
|
|
|
|
|
if (name === targetName) {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
const nextTab = tabNames[index + 1] || tabNames[index - 1] || state.queryTab.name;
|
2022-01-19 15:10:17 +08:00
|
|
|
|
if (nextTab) {
|
|
|
|
|
|
activeName = nextTab;
|
|
|
|
|
|
}
|
2022-01-17 17:10:38 +08:00
|
|
|
|
}
|
2022-01-19 15:10:17 +08:00
|
|
|
|
});
|
|
|
|
|
|
state.activeName = activeName;
|
|
|
|
|
|
delete state.dataTabs[targetName];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 数据tab点击
|
|
|
|
|
|
*/
|
|
|
|
|
|
const onDataTabClick = (tab: any) => {
|
|
|
|
|
|
const name = tab.props.name;
|
|
|
|
|
|
// 不是查询tab,则为表数据tab,同时赋值当前表名,用于在线修改表数据等
|
2022-01-20 18:01:11 +08:00
|
|
|
|
if (name != state.queryTab.name) {
|
2022-01-19 15:10:17 +08:00
|
|
|
|
state.nowTableName = name;
|
2022-01-17 17:10:38 +08:00
|
|
|
|
} else {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
state.nowTableName = state.queryTab.nowTableName;
|
2022-01-17 17:10:38 +08:00
|
|
|
|
}
|
2021-07-28 18:03:19 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2021-11-25 14:34:15 +08:00
|
|
|
|
const beforeUpload = (file: File) => {
|
|
|
|
|
|
if (!state.dbId) {
|
|
|
|
|
|
ElMessage.error('请先选择数据库');
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
ElMessage.success(`'${file.name}' 正在上传执行, 请关注结果通知`);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 执行sql成功
|
|
|
|
|
|
const execSqlFileSuccess = (res: any) => {
|
|
|
|
|
|
if (res.code !== 200) {
|
|
|
|
|
|
ElMessage.error(res.msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取sql文件上传执行url
|
|
|
|
|
|
const getUploadSqlFileUrl = () => {
|
|
|
|
|
|
return `${config.baseApiUrl}/dbs/${state.dbId}/exec-sql-file`;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
const flexColumnWidth = (str: any, tableData: any, flag = 'equal') => {
|
|
|
|
|
|
// str为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
|
|
|
|
|
|
// flag为可选值,可不传该参数,传参时可选'max'或'equal',默认为'max'
|
|
|
|
|
|
// flag为'max'则设置列宽适配该列中最长的内容,flag为'equal'则设置列宽适配该列中第一行内容的长度。
|
|
|
|
|
|
str = str + '';
|
|
|
|
|
|
let columnContent = '';
|
|
|
|
|
|
if (!tableData || !tableData.length || tableData.length === 0 || tableData === undefined) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!str || !str.length || str.length === 0 || str === undefined) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (flag === 'equal') {
|
|
|
|
|
|
// 获取该列中第一个不为空的数据(内容)
|
|
|
|
|
|
for (let i = 0; i < tableData.length; i++) {
|
|
|
|
|
|
if (tableData[i][str].length > 0) {
|
|
|
|
|
|
columnContent = tableData[i][str];
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-06-07 17:22:07 +08:00
|
|
|
|
} else {
|
2021-07-28 18:03:19 +08:00
|
|
|
|
// 获取该列中最长的数据(内容)
|
|
|
|
|
|
let index = 0;
|
|
|
|
|
|
for (let i = 0; i < tableData.length; i++) {
|
|
|
|
|
|
if (tableData[i][str] === null) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const now_temp = tableData[i][str] + '';
|
|
|
|
|
|
const max_temp = tableData[index][str] + '';
|
|
|
|
|
|
if (now_temp.length > max_temp.length) {
|
|
|
|
|
|
index = i;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
columnContent = tableData[index][str];
|
|
|
|
|
|
}
|
|
|
|
|
|
// 以下分配的单位长度可根据实际需求进行调整
|
|
|
|
|
|
let flexWidth = 0;
|
|
|
|
|
|
for (const char of columnContent) {
|
|
|
|
|
|
if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
|
|
|
|
|
|
// 如果是英文字符,为字符分配8个单位宽度
|
|
|
|
|
|
flexWidth += 8;
|
|
|
|
|
|
} else if (char >= '\u4e00' && char <= '\u9fa5') {
|
|
|
|
|
|
// 如果是中文字符,为字符分配15个单位宽度
|
2021-11-25 14:34:15 +08:00
|
|
|
|
flexWidth += 16;
|
2021-07-28 18:03:19 +08:00
|
|
|
|
} else {
|
2021-11-25 14:34:15 +08:00
|
|
|
|
// 其他种类字符,为字符分配10个单位宽度
|
|
|
|
|
|
flexWidth += 10;
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
2021-06-07 17:22:07 +08:00
|
|
|
|
}
|
2021-07-28 18:03:19 +08:00
|
|
|
|
if (flexWidth < 80) {
|
|
|
|
|
|
// 设置最小宽度
|
|
|
|
|
|
flexWidth = 80;
|
|
|
|
|
|
}
|
2021-12-20 20:42:52 +08:00
|
|
|
|
if (flexWidth > 500) {
|
2021-07-28 18:03:19 +08:00
|
|
|
|
// 设置最大宽度
|
2021-12-20 20:42:52 +08:00
|
|
|
|
flexWidth = 500;
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
return flexWidth + 'px';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取sql,如果有鼠标选中,则返回选中内容,否则返回输入框内所有内容
|
|
|
|
|
|
*/
|
|
|
|
|
|
const getSql = () => {
|
|
|
|
|
|
// 没有选中的文本,则为全部文本
|
|
|
|
|
|
let selectSql = codemirror.value.getSelection();
|
|
|
|
|
|
if (selectSql == '') {
|
|
|
|
|
|
selectSql = state.sql;
|
|
|
|
|
|
}
|
|
|
|
|
|
return selectSql;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 更改数据库事件
|
|
|
|
|
|
*/
|
|
|
|
|
|
const changeDb = (id: number) => {
|
|
|
|
|
|
if (!id) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
clearDb();
|
|
|
|
|
|
dbApi.tableMetadata.request({ id }).then((res) => {
|
|
|
|
|
|
state.tableMetadata = res;
|
|
|
|
|
|
// 赋值第一个表信息
|
|
|
|
|
|
if (state.tableMetadata.length > 0) {
|
|
|
|
|
|
state.tableName = state.tableMetadata[0]['tableName'];
|
2022-01-19 15:10:17 +08:00
|
|
|
|
changeTable(state.tableName, false);
|
2021-06-07 17:22:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
dbApi.hintTables
|
|
|
|
|
|
.request({
|
|
|
|
|
|
id: state.dbId,
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((res) => {
|
|
|
|
|
|
state.cmOptions.hintOptions.tables = res;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2021-12-20 20:42:52 +08:00
|
|
|
|
getSqlNames();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2022-01-19 15:10:17 +08:00
|
|
|
|
// 选择表事件
|
|
|
|
|
|
const changeTable = async (tableName: string, execSelectSql: boolean = true) => {
|
|
|
|
|
|
if (tableName == '') {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-01-20 18:01:11 +08:00
|
|
|
|
state.columnMetadata = (await getColumns(tableName)) as any;
|
2022-01-19 15:10:17 +08:00
|
|
|
|
|
|
|
|
|
|
if (!execSelectSql) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 执行sql,并新增tab
|
|
|
|
|
|
state.nowTableName = tableName;
|
|
|
|
|
|
state.activeName = tableName;
|
|
|
|
|
|
let tab = state.dataTabs[tableName];
|
2022-01-20 18:01:11 +08:00
|
|
|
|
// 如果存在该表tab,则直接返回
|
|
|
|
|
|
if (tab) {
|
|
|
|
|
|
return;
|
2022-01-19 15:10:17 +08:00
|
|
|
|
}
|
2022-01-20 18:01:11 +08:00
|
|
|
|
|
|
|
|
|
|
tab = {
|
|
|
|
|
|
label: tableName,
|
|
|
|
|
|
name: tableName,
|
|
|
|
|
|
execRes: {
|
|
|
|
|
|
tableColumn: [],
|
|
|
|
|
|
data: [],
|
|
|
|
|
|
emptyResText: '执行中...',
|
|
|
|
|
|
},
|
|
|
|
|
|
querySql: `SELECT * FROM ${tableName} LIMIT ${state.defalutLimit}`,
|
|
|
|
|
|
};
|
2022-01-19 15:10:17 +08:00
|
|
|
|
state.dataTabs[tableName] = tab;
|
2022-01-20 18:01:11 +08:00
|
|
|
|
|
2022-01-19 15:10:17 +08:00
|
|
|
|
state.dataTabs[tableName].execRes.tableColumn = [];
|
|
|
|
|
|
state.dataTabs[tableName].execRes.data = [];
|
|
|
|
|
|
|
2022-01-20 18:01:11 +08:00
|
|
|
|
onRefresh(tableName);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取表的所有列信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
const getColumns = async (tableName: string) => {
|
|
|
|
|
|
// 优先从 table map中获取
|
|
|
|
|
|
let columns = tableMap.get(tableName);
|
|
|
|
|
|
if (columns) {
|
|
|
|
|
|
return columns;
|
|
|
|
|
|
}
|
|
|
|
|
|
columns = await dbApi.columnMetadata.request({
|
|
|
|
|
|
id: state.dbId,
|
|
|
|
|
|
tableName: tableName,
|
|
|
|
|
|
});
|
|
|
|
|
|
tableMap.set(tableName, columns);
|
|
|
|
|
|
return columns;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const onRefresh = async (tableName: string) => {
|
|
|
|
|
|
const colAndData: any = await runSql(state.dataTabs[tableName].querySql);
|
2022-01-19 15:10:17 +08:00
|
|
|
|
state.dataTabs[tableName].execRes.emptyResText = '没有数据';
|
|
|
|
|
|
state.dataTabs[tableName].execRes.tableColumn = colAndData.colNames;
|
|
|
|
|
|
state.dataTabs[tableName].execRes.data = colAndData.res;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2022-01-20 18:01:11 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 提交事务,用于没有开启自动提交事务
|
|
|
|
|
|
*/
|
|
|
|
|
|
const onCommit = () => {
|
|
|
|
|
|
runSql('COMMIT;');
|
|
|
|
|
|
ElMessage.success('COMMIT success');
|
2021-12-20 20:42:52 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2022-01-19 15:10:17 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 表排序字段变更
|
|
|
|
|
|
*/
|
|
|
|
|
|
const onTableSortChange = async (sort: any) => {
|
|
|
|
|
|
if (!state.nowTableName) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-01-20 18:01:11 +08:00
|
|
|
|
const tableName = state.activeName;
|
2022-01-19 15:10:17 +08:00
|
|
|
|
const sortType = sort.order == 'descending' ? 'DESC' : 'ASC';
|
2022-01-20 18:01:11 +08:00
|
|
|
|
|
|
|
|
|
|
state.dataTabs[state.activeName].querySql = `SELECT * FROM ${tableName} ORDER BY ${sort.prop} ${sortType} LIMIT ${state.defalutLimit}`;
|
|
|
|
|
|
onRefresh(tableName);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const changeSqlTemplate = () => {
|
|
|
|
|
|
getUserSql();
|
2022-01-19 15:10:17 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2022-01-17 17:10:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取用户保存的sql模板内容
|
|
|
|
|
|
*/
|
2021-12-20 20:42:52 +08:00
|
|
|
|
const getUserSql = () => {
|
|
|
|
|
|
notNull(state.dbId, '请先选择数据库');
|
|
|
|
|
|
dbApi.getSql.request({ id: state.dbId, type: 1, name: state.sqlName }).then((res) => {
|
2021-06-07 17:22:07 +08:00
|
|
|
|
if (res) {
|
|
|
|
|
|
state.sql = res.sql;
|
2021-12-20 20:42:52 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
state.sql = '';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2022-01-17 17:10:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取用户保存的sql模板名称
|
|
|
|
|
|
*/
|
2021-12-20 20:42:52 +08:00
|
|
|
|
const getSqlNames = () => {
|
|
|
|
|
|
dbApi.getSqlNames
|
|
|
|
|
|
.request({
|
|
|
|
|
|
id: state.dbId,
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((res) => {
|
|
|
|
|
|
if (res && res.length > 0) {
|
|
|
|
|
|
state.sqlNames = res.map((r: any) => r.name);
|
|
|
|
|
|
state.sqlName = state.sqlNames[0];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
state.sqlNames = ['default'] as any;
|
|
|
|
|
|
state.sqlName = 'default';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
getUserSql();
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const saveSql = async () => {
|
|
|
|
|
|
notEmpty(state.sql, 'sql内容不能为空');
|
|
|
|
|
|
notNull(state.dbId, '请先选择数据库');
|
|
|
|
|
|
await dbApi.saveSql.request({ id: state.dbId, sql: state.sql, type: 1, name: state.sqlName });
|
|
|
|
|
|
ElMessage.success('保存成功');
|
|
|
|
|
|
|
|
|
|
|
|
dbApi.getSqlNames
|
|
|
|
|
|
.request({
|
|
|
|
|
|
id: state.dbId,
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((res) => {
|
|
|
|
|
|
if (res) {
|
|
|
|
|
|
state.sqlNames = res.map((r: any) => r.name);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const deleteSql = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await ElMessageBox.confirm(`确定删除【${state.sqlName}】该SQL模板?`, '提示', {
|
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
|
type: 'warning',
|
|
|
|
|
|
});
|
|
|
|
|
|
await dbApi.deleteDbSql.request({ id: state.dbId, name: state.sqlName });
|
|
|
|
|
|
ElMessage.success('删除成功');
|
|
|
|
|
|
getSqlNames();
|
|
|
|
|
|
} catch (err) {}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
// 清空数据库事件
|
|
|
|
|
|
const clearDb = () => {
|
|
|
|
|
|
state.tableName = '';
|
2022-01-20 18:01:11 +08:00
|
|
|
|
state.nowTableName = '';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
state.tableMetadata = [];
|
|
|
|
|
|
state.columnMetadata = [];
|
2022-01-19 15:10:17 +08:00
|
|
|
|
state.dataTabs = {};
|
|
|
|
|
|
state.sql = '';
|
|
|
|
|
|
state.sqlNames = [];
|
2022-01-20 18:01:11 +08:00
|
|
|
|
state.activeName = state.queryTab.name;
|
|
|
|
|
|
state.queryTab.execRes.data = [];
|
|
|
|
|
|
state.queryTab.execRes.tableColumn = [];
|
2021-07-28 18:03:19 +08:00
|
|
|
|
state.cmOptions.hintOptions.tables = [];
|
2022-01-20 18:01:11 +08:00
|
|
|
|
tableMap.clear();
|
2021-06-07 17:22:07 +08:00
|
|
|
|
};
|
2022-01-20 18:01:11 +08:00
|
|
|
|
|
|
|
|
|
|
const onDataSelectionChange = (datas: []) => {
|
|
|
|
|
|
if (isQueryTab()) {
|
|
|
|
|
|
state.queryTab.selectionDatas = datas;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
state.dataTabs[state.activeName].selectionDatas = datas;
|
2022-01-19 17:23:28 +08:00
|
|
|
|
}
|
2022-01-20 18:01:11 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 执行删除数据事件
|
|
|
|
|
|
*/
|
|
|
|
|
|
const onDeleteData = async () => {
|
|
|
|
|
|
const queryTab = isQueryTab();
|
|
|
|
|
|
const deleteDatas = queryTab ? state.queryTab.selectionDatas : state.dataTabs[state.activeName].selectionDatas;
|
|
|
|
|
|
isTrue(deleteDatas && deleteDatas.length > 0, '请先选择要删除的数据');
|
|
|
|
|
|
const primaryKey = await getTablePrimaryKeyColume(state.nowTableName);
|
|
|
|
|
|
const ids = deleteDatas.map((d: any) => `'${d[primaryKey]}'`).join(',');
|
|
|
|
|
|
const sql = `DELETE FROM ${state.nowTableName} WHERE ${primaryKey} IN (${ids})`;
|
|
|
|
|
|
|
|
|
|
|
|
promptExeSql(sql, null, () => {
|
|
|
|
|
|
if (!queryTab) {
|
|
|
|
|
|
state.dataTabs[state.activeName].execRes.data = state.dataTabs[state.activeName].execRes.data.filter(
|
|
|
|
|
|
(d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKey] == d[primaryKey]) != -1)
|
|
|
|
|
|
);
|
|
|
|
|
|
state.dataTabs[state.activeName].selectionDatas = [];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
state.queryTab.execRes.data = state.queryTab.execRes.data.filter(
|
|
|
|
|
|
(d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKey] == d[primaryKey]) != -1)
|
|
|
|
|
|
);
|
|
|
|
|
|
state.queryTab.selectionDatas = [];
|
2022-01-19 17:23:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
2022-01-20 18:01:11 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 是否为查询tab
|
|
|
|
|
|
*/
|
|
|
|
|
|
const isQueryTab = () => {
|
|
|
|
|
|
return state.activeName == state.queryTab.name;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2022-01-16 05:19:44 +08:00
|
|
|
|
// 监听单元格点击事件
|
|
|
|
|
|
const cellClick = (row: any, column: any, cell: any, event: any) => {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
// 如果当前操作的表名不存在 或者 当前列的property不存在(如多选框),则不允许修改当前单元格内容
|
|
|
|
|
|
if (!state.nowTableName || !column.property) {
|
2022-01-17 17:10:38 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-01-16 05:19:44 +08:00
|
|
|
|
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);
|
2022-01-17 17:10:38 +08:00
|
|
|
|
// 将表格width也赋值于输入框,避免输入框长度超过表格长度
|
|
|
|
|
|
input.setAttribute('style', 'height:30px;' + div.getAttribute('style'));
|
2022-01-16 05:19:44 +08:00
|
|
|
|
cell.replaceChildren(input);
|
|
|
|
|
|
input.focus();
|
2022-01-20 18:01:11 +08:00
|
|
|
|
input.addEventListener('blur', async () => {
|
2022-01-16 05:19:44 +08:00
|
|
|
|
div.innerText = input.value;
|
|
|
|
|
|
cell.replaceChildren(div);
|
|
|
|
|
|
if (input.value !== text) {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
const primaryKey = await getTablePrimaryKeyColume(state.nowTableName);
|
2022-01-17 17:10:38 +08:00
|
|
|
|
const sql = `UPDATE ${state.nowTableName} SET ${column.rawColumnKey} = '${input.value}' WHERE ${primaryKey} = '${row[primaryKey]}'`;
|
|
|
|
|
|
promptExeSql(sql, () => {
|
|
|
|
|
|
div.innerText = text;
|
2022-01-16 05:19:44 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2022-01-17 17:10:38 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取表主键列名,目前先以默认表字段第一个字段
|
|
|
|
|
|
*/
|
2022-01-20 18:01:11 +08:00
|
|
|
|
const getTablePrimaryKeyColume = async (tableName: string) => {
|
|
|
|
|
|
const cols = await getColumns(tableName);
|
|
|
|
|
|
return cols[0].columnName;
|
2022-01-17 17:10:38 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 弹框提示是否执行sql
|
|
|
|
|
|
*/
|
2022-01-19 17:23:28 +08:00
|
|
|
|
const promptExeSql = (sql: string, cancelFunc: any = null, successFunc: any = null) => {
|
2022-01-17 17:10:38 +08:00
|
|
|
|
ElMessageBox({
|
2022-01-20 18:01:11 +08:00
|
|
|
|
title: '待执行SQL',
|
2022-01-17 17:10:38 +08:00
|
|
|
|
message: h(
|
|
|
|
|
|
'div',
|
|
|
|
|
|
{
|
2022-01-19 17:23:28 +08:00
|
|
|
|
class: 'el-textarea',
|
2022-01-17 17:10:38 +08:00
|
|
|
|
},
|
|
|
|
|
|
[
|
|
|
|
|
|
h('textarea', {
|
2022-01-19 17:23:28 +08:00
|
|
|
|
class: 'el-textarea__inner',
|
|
|
|
|
|
autocomplete: 'off',
|
|
|
|
|
|
rows: 8,
|
2022-01-17 17:10:38 +08:00
|
|
|
|
style: {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
height: '300px',
|
2022-01-17 17:10:38 +08:00
|
|
|
|
width: '100%',
|
|
|
|
|
|
fontWeight: '600',
|
|
|
|
|
|
},
|
|
|
|
|
|
value: sqlFormatter(sql),
|
2022-01-19 17:23:28 +08:00
|
|
|
|
onInput: ($event: any) => (sql = $event.target.value),
|
2022-01-17 17:10:38 +08:00
|
|
|
|
}),
|
|
|
|
|
|
]
|
|
|
|
|
|
),
|
|
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
2022-01-20 18:01:11 +08:00
|
|
|
|
.then(async (action) => {
|
|
|
|
|
|
await runSql(sql);
|
|
|
|
|
|
if (successFunc) {
|
|
|
|
|
|
successFunc();
|
|
|
|
|
|
}
|
2022-01-17 17:10:38 +08:00
|
|
|
|
})
|
|
|
|
|
|
.catch(() => {
|
|
|
|
|
|
if (cancelFunc) {
|
|
|
|
|
|
cancelFunc();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2022-01-16 05:19:44 +08:00
|
|
|
|
// 添加新数据行
|
2022-01-20 18:01:11 +08:00
|
|
|
|
const addRow = async () => {
|
|
|
|
|
|
const tableNmae = state.nowTableName;
|
|
|
|
|
|
const columns = await getColumns(tableNmae);
|
|
|
|
|
|
|
|
|
|
|
|
// key: 字段名,value: 字段名提示
|
2022-01-19 17:23:28 +08:00
|
|
|
|
let obj: any = {};
|
2022-01-20 18:01:11 +08:00
|
|
|
|
columns.forEach((item: any) => {
|
|
|
|
|
|
obj[item.columnName] = `'${item.columnName}[${item.columnType}]${item.nullable == 'YES' ? '' : '[not null]'}'`;
|
2022-01-19 17:23:28 +08:00
|
|
|
|
});
|
2022-01-20 18:01:11 +08:00
|
|
|
|
let columnNames = Object.keys(obj).join(',');
|
2022-01-19 17:23:28 +08:00
|
|
|
|
let values = Object.values(obj).join(',');
|
2022-01-20 18:01:11 +08:00
|
|
|
|
let sql = `INSERT INTO ${state.nowTableName} (${columnNames}) VALUES (${values});`;
|
2022-01-19 17:23:28 +08:00
|
|
|
|
promptExeSql(sql, null, () => {
|
2022-01-20 18:01:11 +08:00
|
|
|
|
onRefresh(tableNmae);
|
2022-01-19 17:23:28 +08:00
|
|
|
|
});
|
|
|
|
|
|
};
|
2021-06-07 17:22:07 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 自动提示功能
|
|
|
|
|
|
*/
|
|
|
|
|
|
const showHint = () => {
|
|
|
|
|
|
codemirror.value.showHint();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 格式化sql
|
|
|
|
|
|
*/
|
|
|
|
|
|
const formatSql = () => {
|
|
|
|
|
|
let selectSql = codemirror.value.getSelection();
|
|
|
|
|
|
// 有选中sql则只格式化选中部分,否则格式化全部
|
|
|
|
|
|
if (selectSql != '') {
|
2022-01-17 17:10:38 +08:00
|
|
|
|
codemirror.value.replaceSelection(sqlFormatter(selectSql));
|
2021-06-07 17:22:07 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
/* 将sql内容进行格式后放入编辑器中*/
|
2022-01-17 17:10:38 +08:00
|
|
|
|
state.sql = sqlFormatter(state.sql);
|
2021-06-07 17:22:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const search = async () => {
|
|
|
|
|
|
const res = await dbApi.dbs.request(state.params);
|
|
|
|
|
|
state.dbs = res.list;
|
|
|
|
|
|
};
|
2022-01-17 17:10:38 +08:00
|
|
|
|
|
2021-12-25 00:58:07 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取选择文字,显示隐藏按钮,防抖
|
|
|
|
|
|
*/
|
2022-01-17 17:10:38 +08:00
|
|
|
|
const getSelection = _.debounce((e: any) => {
|
2021-12-25 00:58:07 +08:00
|
|
|
|
let temp = codemirror.value.getSelection();
|
|
|
|
|
|
if (temp) {
|
|
|
|
|
|
state.btnStyle.display = 'block';
|
|
|
|
|
|
if (!state.btnStyle.left) {
|
2022-01-16 19:40:20 +08:00
|
|
|
|
state.btnStyle.left = e.target.getBoundingClientRect().left - 550 + 'px';
|
|
|
|
|
|
state.btnStyle.top = e.target.getBoundingClientRect().top - 160 + 'px';
|
2021-12-25 00:58:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
state.btnStyle.display = 'none';
|
|
|
|
|
|
state.btnStyle.left = '';
|
|
|
|
|
|
state.btnStyle.top = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 100);
|
2022-01-17 17:10:38 +08:00
|
|
|
|
|
2021-12-25 00:58:07 +08:00
|
|
|
|
const listenMouse = (e: any) => {
|
|
|
|
|
|
getSelection(e);
|
|
|
|
|
|
};
|
2022-01-17 17:10:38 +08:00
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
return {
|
|
|
|
|
|
...toRefs(state),
|
|
|
|
|
|
cmEditor,
|
2021-07-28 18:03:19 +08:00
|
|
|
|
changeProjectEnv,
|
2021-06-07 17:22:07 +08:00
|
|
|
|
inputRead,
|
|
|
|
|
|
changeTable,
|
2022-01-16 05:19:44 +08:00
|
|
|
|
cellClick,
|
2022-01-19 15:10:17 +08:00
|
|
|
|
onRunSql,
|
|
|
|
|
|
removeDataTab,
|
|
|
|
|
|
onDataTabClick,
|
2021-11-25 14:34:15 +08:00
|
|
|
|
beforeUpload,
|
|
|
|
|
|
getUploadSqlFileUrl,
|
|
|
|
|
|
execSqlFileSuccess,
|
2021-07-28 18:03:19 +08:00
|
|
|
|
flexColumnWidth,
|
2021-12-20 20:42:52 +08:00
|
|
|
|
changeSqlTemplate,
|
|
|
|
|
|
deleteSql,
|
2021-06-07 17:22:07 +08:00
|
|
|
|
saveSql,
|
|
|
|
|
|
changeDb,
|
|
|
|
|
|
clearDb,
|
|
|
|
|
|
formatSql,
|
2021-07-28 18:03:19 +08:00
|
|
|
|
onBeforeChange,
|
2021-12-25 00:58:07 +08:00
|
|
|
|
listenMouse,
|
2022-01-20 18:01:11 +08:00
|
|
|
|
onRefresh,
|
|
|
|
|
|
onCommit,
|
2022-01-19 17:23:28 +08:00
|
|
|
|
addRow,
|
2022-01-20 18:01:11 +08:00
|
|
|
|
onDataSelectionChange,
|
|
|
|
|
|
onDeleteData,
|
2022-01-19 15:10:17 +08:00
|
|
|
|
onTableSortChange,
|
2021-06-07 17:22:07 +08:00
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.codesql {
|
2022-01-28 11:30:11 +08:00
|
|
|
|
font-size: 9pt;
|
2022-01-12 16:00:31 +08:00
|
|
|
|
font-weight: 600;
|
2021-06-07 17:22:07 +08:00
|
|
|
|
}
|
2022-01-16 19:40:20 +08:00
|
|
|
|
.el-tabs__header {
|
2022-01-19 15:10:17 +08:00
|
|
|
|
padding: 0 10px;
|
2022-01-16 19:40:20 +08:00
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
}
|
2021-06-07 17:22:07 +08:00
|
|
|
|
</style>
|