mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-28 03:50:25 +08:00
Merge remote-tracking branch 'upstream/dev' into dev_20230206
# Conflicts: # mayfly_go_web/src/views/ops/db/SqlExec.vue # mayfly_go_web/src/views/ops/db/component/InstanceTree.vue # mayfly_go_web/src/views/ops/mongo/MongoInstanceTree.vue
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
"countup.js": "^2.0.7",
|
"countup.js": "^2.0.7",
|
||||||
"cropperjs": "^1.5.11",
|
"cropperjs": "^1.5.11",
|
||||||
"echarts": "^5.4.0",
|
"echarts": "^5.4.0",
|
||||||
"element-plus": "^2.2.26",
|
"element-plus": "^2.2.29",
|
||||||
"jsencrypt": "^3.2.1",
|
"jsencrypt": "^3.2.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
@@ -44,10 +44,10 @@
|
|||||||
"eslint": "^8.5.0",
|
"eslint": "^8.5.0",
|
||||||
"eslint-plugin-vue": "^8.2.0",
|
"eslint-plugin-vue": "^8.2.0",
|
||||||
"prettier": "^2.3.0",
|
"prettier": "^2.3.0",
|
||||||
"sass": "^1.45.1",
|
"sass": "^1.58.0",
|
||||||
"sass-loader": "^12.4.0",
|
"sass-loader": "^13.2.0",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
"vite": "^4.0.4",
|
"vite": "^4.1.1",
|
||||||
"vue-eslint-parser": "^8.0.1"
|
"vue-eslint-parser": "^8.0.1"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
|
function getBaseApiUrl() {
|
||||||
|
let path = window.location.pathname;
|
||||||
|
if (path == '/') {
|
||||||
|
return window.location.host;
|
||||||
|
}
|
||||||
|
return window.location.host + path;
|
||||||
|
}
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
baseApiUrl: `${(window as any).globalConfig.BaseApiUrl}/api`,
|
baseApiUrl: `${(window as any).globalConfig.BaseApiUrl || location.protocol + '//' + getBaseApiUrl()}/api`,
|
||||||
baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${location.host}`}/api`,
|
baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
|
||||||
|
|
||||||
// 系统版本
|
// 系统版本
|
||||||
version: 'v1.3.1'
|
version: 'v1.3.1'
|
||||||
|
|||||||
@@ -4,74 +4,81 @@
|
|||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-button type="primary" icon="plus" @click="addQueryTab" size="small">新建查询</el-button>
|
<el-button type="primary" icon="plus" @click="addQueryTab" size="small">新建查询</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4" style="border-left: 1px solid #eee; margin-top: 10px" >
|
<el-col :span="4" style="border-left: 1px solid #eee; margin-top: 10px">
|
||||||
<InstanceTree
|
<InstanceTree :instance-menu-max-height="state.instanceMenuMaxHeight" :instances="state.instances"
|
||||||
:instance-menu-max-height="state.instanceMenuMaxHeight"
|
@init-load-instances="loadInstances" @change-instance="changeInstance" @change-schema="changeSchema"
|
||||||
:instances="state.instances"
|
@load-table-names="loadSchemaTables" @load-table-data="loadTableData" />
|
||||||
@init-load-instances="loadInstances"
|
|
||||||
@change-instance="changeInstance"
|
|
||||||
@change-schema="changeSchema"
|
|
||||||
@load-table-names="loadSchemaTables"
|
|
||||||
@load-table-data="loadTableData"
|
|
||||||
/>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="20">
|
<el-col :span="20">
|
||||||
<el-container id="data-exec" style="border-left: 1px solid #eee; margin-top: 10px">
|
<el-container id="data-exec" style="border-left: 1px solid #eee; margin-top: 10px">
|
||||||
<el-tabs @tab-remove="removeDataTab" @tab-click="onDataTabClick" style="width: 100%" v-model="state.activeName">
|
<el-tabs @tab-remove="removeDataTab" @tab-click="onDataTabClick" style="width: 100%"
|
||||||
<el-tab-pane closable v-for="q in state.queryTabs" :key="q.id" :label="q.label" :name="q.name" >
|
v-model="state.activeName">
|
||||||
|
<el-tab-pane closable v-for="q in state.queryTabs" :key="q.id" :label="q.label" :name="q.name">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<div class="fl">
|
<div class="fl">
|
||||||
<el-link @click="onRunSql(q.dbId, q.db)" :underline="false" class="ml15" icon="VideoPlay">
|
<el-link @click="onRunSql(q.dbId, q.db)" :underline="false" class="ml15"
|
||||||
|
icon="VideoPlay">
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-tooltip class="box-item" effect="dark" content="format sql" placement="top">
|
<el-tooltip class="box-item" effect="dark" content="format sql"
|
||||||
<el-link @click="formatSql(q.dbId, q.db)" type="primary" :underline="false" icon="MagicStick">
|
placement="top">
|
||||||
|
<el-link @click="formatSql(q.dbId, q.db)" type="primary"
|
||||||
|
:underline="false" icon="MagicStick">
|
||||||
</el-link>
|
</el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-tooltip class="box-item" effect="dark" content="commit" placement="top">
|
<el-tooltip class="box-item" effect="dark" content="commit" placement="top">
|
||||||
<el-link @click="onCommit(q.dbId, q.db)" type="success" :underline="false" icon="CircleCheck">
|
<el-link @click="onCommit(q.dbId, q.db)" type="success"
|
||||||
|
:underline="false" icon="CircleCheck">
|
||||||
</el-link>
|
</el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-upload class="sql-file-exec" :before-upload="beforeUpload"
|
<el-upload class="sql-file-exec" :before-upload="beforeUpload"
|
||||||
:on-success="execSqlFileSuccess" :headers="{ Authorization: token }" :data="{ dbId: q.dbId }" :action="getUploadSqlFileUrl(q.dbId, q.db)" :show-file-list="false" name="file" multiple
|
:on-success="execSqlFileSuccess" :headers="{ Authorization: token }"
|
||||||
:limit="100">
|
:data="{ dbId: q.dbId }" :action="getUploadSqlFileUrl(q.dbId, q.db)"
|
||||||
<el-tooltip class="box-item" effect="dark" content="SQL脚本执行" placement="top">
|
:show-file-list="false" name="file" multiple :limit="100">
|
||||||
<el-link type="success" :underline="false" icon="Document"></el-link>
|
<el-tooltip class="box-item" effect="dark" content="SQL脚本执行"
|
||||||
|
placement="top">
|
||||||
|
<el-link type="success" :underline="false"
|
||||||
|
icon="Document"></el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="float: right" class="fl">
|
<div style="float: right" class="fl">
|
||||||
<el-select v-model="state.sqlName[q.dbId+q.db]" placeholder="选择or输入SQL模板名" @change="changeSqlTemplate(q.dbId, q.db)"
|
<el-select v-model="state.sqlName[q.dbId + q.db]" placeholder="选择or输入SQL模板名"
|
||||||
filterable allow-create default-first-option size="small" class="mr10">
|
@change="changeSqlTemplate(q.dbId, q.db)" filterable allow-create
|
||||||
<el-option v-for="item in state.sqlNames[q.dbId+q.db]" :key="item" :label="item.database"
|
default-first-option size="small" class="mr10">
|
||||||
:value="item">
|
<el-option v-for="item in state.sqlNames[q.dbId + q.db]" :key="item"
|
||||||
|
:label="item.database" :value="item">
|
||||||
{{ item }}
|
{{ item }}
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|
||||||
<el-button @click="saveSql(q.dbId, q.db)" type="primary" icon="document-add" plain size="small">保存
|
<el-button @click="saveSql(q.dbId, q.db)" type="primary" icon="document-add"
|
||||||
|
plain size="small">保存
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="deleteSql(q.dbId, q.db)" type="danger" icon="delete" plain size="small">删除
|
<el-button @click="deleteSql(q.dbId, q.db)" type="danger" icon="delete"
|
||||||
|
plain size="small">删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt5 sqlEditor">
|
<div class="mt5 sqlEditor">
|
||||||
<div :id="'MonacoTextarea-'+ q.id" :style="{ height: state.monacoOptions.height }"></div>
|
<div :id="'MonacoTextarea-' + q.id" :style="{ height: state.monacoOptions.height }">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt5">
|
<div class="mt5">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-link v-if="q.nowTableName" @click="onDeleteData(q.dbId, q.db, q.nowTableName)" class="ml5" type="danger"
|
<el-link v-if="q.nowTableName"
|
||||||
icon="delete" :underline="false"></el-link>
|
@click="onDeleteData(q.dbId, q.db, q.nowTableName)" class="ml5"
|
||||||
|
type="danger" icon="delete" :underline="false"></el-link>
|
||||||
|
|
||||||
<span v-if="q.execRes.data.length > 0">
|
<span v-if="q.execRes.data.length > 0">
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
@@ -80,7 +87,8 @@
|
|||||||
</span>
|
</span>
|
||||||
<span v-if="q.updatedFields.length > 0">
|
<span v-if="q.updatedFields.length > 0">
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
<el-link type="success" :underline="false" @click="submitUpdateFields(q.dbId, q.db, q.nowTableName)"><span
|
<el-link type="success" :underline="false"
|
||||||
|
@click="submitUpdateFields(q.dbId, q.db, q.nowTableName)"><span
|
||||||
style="font-size: 12px">提交</span></el-link>
|
style="font-size: 12px">提交</span></el-link>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="q.updatedFields.length > 0">
|
<span v-if="q.updatedFields.length > 0">
|
||||||
@@ -89,25 +97,24 @@
|
|||||||
style="font-size: 12px">取消</span></el-link>
|
style="font-size: 12px">取消</span></el-link>
|
||||||
</span>
|
</span>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-table @cell-dblclick="(row, column, cell, event) => cellClick(row, column, cell, event, {dbId: q.dbId, db: q.db, tableName: q.nowTableName})"
|
<el-table
|
||||||
@selection-change="onDataSelectionChange" size="small"
|
@cell-dblclick="(row: any, column: any, cell: any, event: any) => cellClick(row, column, cell, event, { dbId: q.dbId, db: q.db, tableName: q.nowTableName })"
|
||||||
:data="q.execRes.data" v-loading="q.loading" element-loading-text="查询中..."
|
@selection-change="onDataSelectionChange" size="small" :data="q.execRes.data"
|
||||||
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改" stripe border class="mt5">
|
v-loading="q.loading" element-loading-text="查询中..."
|
||||||
|
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改" stripe border
|
||||||
|
class="mt5">
|
||||||
<el-table-column v-if="q.execRes.tableColumn.length > 0 && q.nowTableName"
|
<el-table-column v-if="q.execRes.tableColumn.length > 0 && q.nowTableName"
|
||||||
type="selection" width="35" />
|
type="selection" width="35" />
|
||||||
<el-table-column min-width="100" :width="flexColumnWidth(item, q.execRes.data)"
|
<el-table-column min-width="100" :width="flexColumnWidth(item, q.execRes.data)"
|
||||||
align="center" v-for="item in q.execRes.tableColumn" :key="item" :prop="item"
|
align="center" v-for="item in q.execRes.tableColumn" :key="item"
|
||||||
:label="item" show-overflow-tooltip>
|
:prop="item" :label="item" show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-row type="flex" class="mt5" justify="center">
|
<el-row type="flex" class="mt5" justify="center">
|
||||||
<el-pagination
|
<el-pagination v-show="q.execRes.showPage" small :total="q.execRes.total"
|
||||||
v-show="q.execRes.showPage" small
|
@current-change="doRunSql(q.dbId, q.db, q.sql)"
|
||||||
:total="q.execRes.total"
|
|
||||||
@current-change="doRunSql(q.dbId,q.db,q.sql)"
|
|
||||||
layout="prev,pager,next,total,jumper"
|
layout="prev,pager,next,total,jumper"
|
||||||
v-model:current-page="q.execRes.pageNum"
|
v-model:current-page="q.execRes.pageNum" :page-size="defalutLimit">
|
||||||
:page-size="defalutLimit">
|
|
||||||
</el-pagination>
|
</el-pagination>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,39 +122,47 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
|
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label"
|
||||||
|
:name="dt.key">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-link @click="onRefresh(dt.dbId, dt.db,dt.name)" icon="refresh" :underline="false" class="ml5">
|
<el-link @click="onRefresh(dt.dbId, dt.db, dt.name)" icon="refresh"
|
||||||
|
:underline="false" class="ml5">
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-link @click="addRow(dt.dbId, dt.db, dt.name)" type="primary" icon="plus" :underline="false"></el-link>
|
<el-link @click="addRow(dt.dbId, dt.db, dt.name)" type="primary" icon="plus"
|
||||||
|
:underline="false"></el-link>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-link @click="onDeleteData(dt.dbId, dt.db, dt.name)" type="danger" icon="delete" :underline="false"></el-link>
|
<el-link @click="onDeleteData(dt.dbId, dt.db, dt.name)" type="danger" icon="delete"
|
||||||
|
:underline="false"></el-link>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-tooltip class="box-item" effect="dark" content="commit" placement="top">
|
<el-tooltip class="box-item" effect="dark" content="commit" placement="top">
|
||||||
<el-link @click="onCommit(dt.dbId, dt.db)" type="success" icon="CircleCheck" :underline="false">
|
<el-link @click="onCommit(dt.dbId, dt.db)" type="success" icon="CircleCheck"
|
||||||
|
:underline="false">
|
||||||
</el-link>
|
</el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-tooltip class="box-item" effect="dark" content="生成insert sql" placement="top">
|
<el-tooltip class="box-item" effect="dark" content="生成insert sql" placement="top">
|
||||||
<el-link @click="onGenerateInsertSql(dt.dbId, dt.db, dt.name)" type="success" :underline="false">gi</el-link>
|
<el-link @click="onGenerateInsertSql(dt.dbId, dt.db, dt.name)" type="success"
|
||||||
|
:underline="false">gi</el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-tooltip v-if="state.updatedFields[state.nowTableName]?.length > 0" class="box-item"
|
<el-tooltip v-if="state.updatedFields[state.nowTableName]?.length > 0"
|
||||||
effect="dark" content="提交修改" placement="top">
|
class="box-item" effect="dark" content="提交修改" placement="top">
|
||||||
<el-link @click="submitUpdateFields(dt.dbId, dt.db, dt.name)" type="success" :underline="false">提交</el-link>
|
<el-link @click="submitUpdateFields(dt.dbId, dt.db, dt.name)" type="success"
|
||||||
|
:underline="false">提交</el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-divider v-if="state.updatedFields[state.nowTableName]?.length > 0" direction="vertical"
|
<el-divider v-if="state.updatedFields[state.nowTableName]?.length > 0"
|
||||||
border-style="dashed" />
|
direction="vertical" border-style="dashed" />
|
||||||
<el-tooltip v-if="state.updatedFields[state.nowTableName]?.length > 0" class="box-item"
|
<el-tooltip v-if="state.updatedFields[state.nowTableName]?.length > 0"
|
||||||
effect="dark" content="取消修改" placement="top">
|
class="box-item" effect="dark" content="取消修改" placement="top">
|
||||||
<el-link @click="cancelUpdateFields" type="warning" :underline="false">取消</el-link>
|
<el-link @click="cancelUpdateFields" type="warning"
|
||||||
|
:underline="false">取消</el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
@@ -164,9 +179,11 @@
|
|||||||
onConditionRowClick(event, dt);
|
onConditionRowClick(event, dt);
|
||||||
}
|
}
|
||||||
" style="cursor: pointer">
|
" style="cursor: pointer">
|
||||||
<el-table-column property="columnName" label="列名" show-overflow-tooltip>
|
<el-table-column property="columnName" label="列名"
|
||||||
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column property="columnComment" label="备注" show-overflow-tooltip>
|
<el-table-column property="columnComment" label="备注"
|
||||||
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
@@ -179,15 +196,16 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-table @cell-dblclick="(row, column, cell, event) => cellClick(row, column, cell, event, {dbId: dt.dbId, db: dt.db, tableName: dt.name})"
|
<el-table
|
||||||
@sort-change="sort => onTableSortChange(dt.dbId, dt.db, sort, dt.name)"
|
@cell-dblclick="(row: any, column: any, cell: any, event: any) => cellClick(row, column, cell, event, { dbId: dt.dbId, db: dt.db, tableName: dt.name })"
|
||||||
|
@sort-change="(sort: any) => onTableSortChange(dt.dbId, dt.db, sort, dt.name)"
|
||||||
@selection-change="onDataSelectionChange" :data="dt.datas" size="small"
|
@selection-change="onDataSelectionChange" :data="dt.datas" size="small"
|
||||||
:max-height="state.dataTabsTableHeight" v-loading="dt.loading" element-loading-text="查询中..."
|
:max-height="state.dataTabsTableHeight" v-loading="dt.loading"
|
||||||
empty-text="暂无数据" stripe border class="mt5">
|
element-loading-text="查询中..." empty-text="暂无数据" stripe border class="mt5">
|
||||||
<el-table-column v-if="dt.datas.length > 0" type="selection" width="35" />
|
<el-table-column v-if="dt.datas.length > 0" type="selection" width="35" />
|
||||||
<el-table-column min-width="100" :width="flexColumnWidth(item, dt.datas)" align="center"
|
<el-table-column min-width="100" :width="flexColumnWidth(item, dt.datas)" align="center"
|
||||||
v-for="item in dt.columnNames" :key="item" :prop="item" :label="item" show-overflow-tooltip
|
v-for="item in dt.columnNames" :key="item" :prop="item" :label="item"
|
||||||
:sortable="state.nowTableName !== '' ? 'custom' : false">
|
show-overflow-tooltip :sortable="state.nowTableName !== '' ? 'custom' : false">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-tooltip raw-content placement="top" effect="customized">
|
<el-tooltip raw-content placement="top" effect="customized">
|
||||||
<template #content> {{ getColumnTip(dt.name, item) }} </template>
|
<template #content> {{ getColumnTip(dt.name, item) }} </template>
|
||||||
@@ -201,7 +219,7 @@
|
|||||||
layout="prev, pager, next, total, jumper" v-model:current-page="dt.pageNum"
|
layout="prev, pager, next, total, jumper" v-model:current-page="dt.pageNum"
|
||||||
:page-size="defalutLimit"></el-pagination>
|
:page-size="defalutLimit"></el-pagination>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div style=" font-size: 12px; padding: 0 10px; color: #606266"><span>{{dt.sql}}</span></div>
|
<div style=" font-size: 12px; padding: 0 10px; color: #606266"><span>{{ dt.sql }}</span></div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-container>
|
</el-container>
|
||||||
@@ -232,29 +250,30 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog @close="state.genSqlDialog.visible = false" v-model="state.genSqlDialog.visible" title="SQL" width="1000px">
|
<el-dialog @close="state.genSqlDialog.visible = false" v-model="state.genSqlDialog.visible" title="SQL"
|
||||||
|
width="1000px">
|
||||||
<el-input v-model="state.genSqlDialog.sql" type="textarea" rows="20" />
|
<el-input v-model="state.genSqlDialog.sql" type="textarea" rows="20" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {computed, nextTick, onMounted, reactive, watch} from 'vue';
|
import { computed, nextTick, onMounted, reactive, watch } from 'vue';
|
||||||
import {dbApi} from './api';
|
import { dbApi } from './api';
|
||||||
|
|
||||||
import {format as sqlFormatter} from 'sql-formatter';
|
import { format as sqlFormatter } from 'sql-formatter';
|
||||||
import {isTrue, notBlank, notEmpty} from '@/common/assert';
|
import { isTrue, notBlank, notEmpty } from '@/common/assert';
|
||||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import config from '@/common/config';
|
import config from '@/common/config';
|
||||||
import {getSession} from '@/common/utils/storage';
|
import { getSession } from '@/common/utils/storage';
|
||||||
import SqlExecBox from './component/SqlExecBox';
|
import SqlExecBox from './component/SqlExecBox';
|
||||||
import {dateStrFormat} from '@/common/utils/date.ts';
|
import { dateStrFormat } from '@/common/utils/date.ts';
|
||||||
import {useStore} from '@/store/index.ts';
|
import { useStore } from '@/store/index.ts';
|
||||||
|
|
||||||
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker';
|
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker';
|
||||||
import {language as sqlLanguage} from 'monaco-editor/esm/vs/basic-languages/mysql/mysql.js';
|
import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/mysql/mysql.js';
|
||||||
import * as monaco from 'monaco-editor';
|
import * as monaco from 'monaco-editor';
|
||||||
import {editor, languages, Position} from 'monaco-editor';
|
import { editor, languages, Position } from 'monaco-editor';
|
||||||
|
|
||||||
// 主题仓库 https://github.com/brijeshb42/monaco-themes
|
// 主题仓库 https://github.com/brijeshb42/monaco-themes
|
||||||
// 主题例子 https://editor.bitwiser.in/
|
// 主题例子 https://editor.bitwiser.in/
|
||||||
@@ -360,14 +379,14 @@ const state = reactive({
|
|||||||
dbTables: {},
|
dbTables: {},
|
||||||
},
|
},
|
||||||
updatedFields: {} as { [tableName: string]: UpdateFieldsMeta[] },// 各个tab表被修改的字段信息
|
updatedFields: {} as { [tableName: string]: UpdateFieldsMeta[] },// 各个tab表被修改的字段信息
|
||||||
instances:{
|
instances: {
|
||||||
tags:{},
|
tags: {},
|
||||||
tree:{},
|
tree: {},
|
||||||
dbs:{},
|
dbs: {},
|
||||||
tables:{},
|
tables: {},
|
||||||
sqls:{},
|
sqls: {},
|
||||||
},
|
},
|
||||||
instanceMenuMaxHeight:'850px'
|
instanceMenuMaxHeight: '850px'
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取布局配置信息
|
// 获取布局配置信息
|
||||||
@@ -471,7 +490,7 @@ const initMonacoEditor = (queryTab: any) => {
|
|||||||
triggerCharacters: ['.'],
|
triggerCharacters: ['.'],
|
||||||
provideCompletionItems: async (model: editor.ITextModel, position: Position): Promise<languages.CompletionList | null | undefined> => {
|
provideCompletionItems: async (model: editor.ITextModel, position: Position): Promise<languages.CompletionList | null | undefined> => {
|
||||||
let word = model.getWordUntilPosition(position);
|
let word = model.getWordUntilPosition(position);
|
||||||
let {dbId, db} = state.activeNameMap[state.activeName]
|
let { dbId, db } = state.activeNameMap[state.activeName]
|
||||||
const { lineNumber, column } = position
|
const { lineNumber, column } = position
|
||||||
const { startColumn, endColumn } = word
|
const { startColumn, endColumn } = word
|
||||||
|
|
||||||
@@ -546,11 +565,11 @@ const initMonacoEditor = (queryTab: any) => {
|
|||||||
let table = tableInfo.tableName
|
let table = tableInfo.tableName
|
||||||
let db = tableInfo.dbName
|
let db = tableInfo.dbName
|
||||||
// 取出表名并提示
|
// 取出表名并提示
|
||||||
let dbs = state.monacoOptions.dbTables[dbId+db]
|
let dbs = state.monacoOptions.dbTables[dbId + db]
|
||||||
let columns = dbs ? (dbs[table] || []) : [];
|
let columns = dbs ? (dbs[table] || []) : [];
|
||||||
if ((!columns || columns.length === 0) && db) {
|
if ((!columns || columns.length === 0) && db) {
|
||||||
state.monacoOptions.dbTables[dbId+db] = await loadHintTables(dbId, db)
|
state.monacoOptions.dbTables[dbId + db] = await loadHintTables(dbId, db)
|
||||||
dbs = state.monacoOptions.dbTables[dbId+db]
|
dbs = state.monacoOptions.dbTables[dbId + db]
|
||||||
columns = dbs ? (dbs[table] || []) : [];
|
columns = dbs ? (dbs[table] || []) : [];
|
||||||
}
|
}
|
||||||
let suggestions: languages.CompletionItem[] = []
|
let suggestions: languages.CompletionItem[] = []
|
||||||
@@ -724,7 +743,7 @@ onMounted(() => {
|
|||||||
const setHeight = () => {
|
const setHeight = () => {
|
||||||
// 默认300px
|
// 默认300px
|
||||||
state.monacoOptions.height = window.innerHeight - 550 + 'px'
|
state.monacoOptions.height = window.innerHeight - 550 + 'px'
|
||||||
state.dataTabsTableHeight = window.innerHeight - 219;
|
state.dataTabsTableHeight = window.innerHeight - 219 - 36;
|
||||||
state.instanceMenuMaxHeight = window.innerHeight - 140 + 'px';
|
state.instanceMenuMaxHeight = window.innerHeight - 140 + 'px';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -789,27 +808,27 @@ const doRunSql = async (dbId: any, db: string, sql: string, execRemark?: string)
|
|||||||
state.queryTabs[key].loading = true;
|
state.queryTabs[key].loading = true;
|
||||||
|
|
||||||
// 执行新sql,还原分页信息
|
// 执行新sql,还原分页信息
|
||||||
if(state.queryTabs[key].sql !== sql){
|
if (state.queryTabs[key].sql !== sql) {
|
||||||
state.queryTabs[key].execRes.total = 0
|
state.queryTabs[key].execRes.total = 0
|
||||||
state.queryTabs[key].execRes.pageNum = 1
|
state.queryTabs[key].execRes.pageNum = 1
|
||||||
state.queryTabs[key].sql = sql;
|
state.queryTabs[key].sql = sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 干掉sql最后的分号
|
// 干掉sql最后的分号
|
||||||
if(sql.endsWith(';')){
|
if (sql.endsWith(';')) {
|
||||||
sql = sql.substring(0, sql.length -1)
|
sql = sql.substring(0, sql.length - 1)
|
||||||
}
|
}
|
||||||
// 给sql添加limit (pageNum-1)*pageSize, pageSize
|
// 给sql添加limit (pageNum-1)*pageSize, pageSize
|
||||||
sql = sql.trim().toLowerCase();
|
sql = sql.trim().toLowerCase();
|
||||||
let countSql = `select count(*) ct from (${sql}) a`
|
let countSql = `select count(*) ct from (${sql}) a`
|
||||||
if (sql.startsWith('select') && sql.indexOf('limit') < 0){
|
if (sql.startsWith('select') && sql.indexOf('limit') < 0) {
|
||||||
state.queryTabs[key].execRes.showPage = true
|
state.queryTabs[key].execRes.showPage = true
|
||||||
switch (state.dbType) {
|
switch (state.dbType) {
|
||||||
case 'mysql':
|
case 'mysql':
|
||||||
sql += ` limit ${(state.queryTabs[key].execRes.pageNum-1)*defalutLimit}, ${defalutLimit} `
|
sql += ` limit ${(state.queryTabs[key].execRes.pageNum - 1) * defalutLimit}, ${defalutLimit} `
|
||||||
break;
|
break;
|
||||||
case 'postgres':
|
case 'postgres':
|
||||||
sql += ` OFFSET ${(state.queryTabs[key].execRes.pageNum-1)*defalutLimit} LIMIT ${defalutLimit} `
|
sql += ` OFFSET ${(state.queryTabs[key].execRes.pageNum - 1) * defalutLimit} LIMIT ${defalutLimit} `
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -817,15 +836,15 @@ const doRunSql = async (dbId: any, db: string, sql: string, execRemark?: string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const colAndData: any = await runSql(dbId, db, sql, execRemark);
|
const colAndData: any = await runSql(dbId, db, sql, execRemark);
|
||||||
if(!colAndData.res || colAndData.res.length===0){
|
if (!colAndData.res || colAndData.res.length === 0) {
|
||||||
ElMessage.warning('暂无数据')
|
ElMessage.warning('暂无数据')
|
||||||
}
|
}
|
||||||
state.queryTabs[key].execRes.data = colAndData.res;
|
state.queryTabs[key].execRes.data = colAndData.res;
|
||||||
if(colAndData.res && colAndData.res.length == defalutLimit){
|
if (colAndData.res && colAndData.res.length == defalutLimit) {
|
||||||
const countRes = await runSql(dbId, db, countSql);
|
const countRes = await runSql(dbId, db, countSql);
|
||||||
state.queryTabs[key].execRes.total = countRes.res[0].ct
|
state.queryTabs[key].execRes.total = countRes.res[0].ct
|
||||||
}else{
|
} else {
|
||||||
state.queryTabs[key].execRes.total = (state.queryTabs[key].execRes.pageNum-1)*defalutLimit + colAndData.res.length
|
state.queryTabs[key].execRes.total = (state.queryTabs[key].execRes.pageNum - 1) * defalutLimit + colAndData.res.length
|
||||||
}
|
}
|
||||||
state.queryTabs[key].execRes.tableColumn = colAndData.colNames;
|
state.queryTabs[key].execRes.tableColumn = colAndData.colNames;
|
||||||
state.queryTabs[key].loading = false;
|
state.queryTabs[key].loading = false;
|
||||||
@@ -899,7 +918,7 @@ const removeDataTab = (targetName: string) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!matched){
|
if (!matched) {
|
||||||
const queryTabNames = Object.keys(state.queryTabs);
|
const queryTabNames = Object.keys(state.queryTabs);
|
||||||
queryTabNames.forEach((name: string, index: number) => {
|
queryTabNames.forEach((name: string, index: number) => {
|
||||||
if (name === targetName) {
|
if (name === targetName) {
|
||||||
@@ -1054,12 +1073,12 @@ const getSql = () => {
|
|||||||
return res
|
return res
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadSchemaMeta = async (dbId: any, db: string)=>{
|
const loadSchemaMeta = async (dbId: any, db: string) => {
|
||||||
// 加载数据库下所有表
|
// 加载数据库下所有表
|
||||||
state.instances.tables[dbId+db] = state.instances.tables[dbId+db] || await loadTableMetadata(dbId, db)
|
state.instances.tables[dbId + db] = state.instances.tables[dbId + db] || await loadTableMetadata(dbId, db)
|
||||||
|
|
||||||
// 加载数据库下所有表字段信息
|
// 加载数据库下所有表字段信息
|
||||||
state.monacoOptions.dbTables[dbId+db] = state.monacoOptions.dbTables[dbId+db] || await loadHintTables(dbId, db)
|
state.monacoOptions.dbTables[dbId + db] = state.monacoOptions.dbTables[dbId + db] || await loadHintTables(dbId, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadTableMetadata = async (dbId: any, db: string) => {
|
const loadTableMetadata = async (dbId: any, db: string) => {
|
||||||
@@ -1082,15 +1101,15 @@ const changeTable = async (tableName: string, execSelectSql: boolean = true) =>
|
|||||||
// 执行sql,并新增tab
|
// 执行sql,并新增tab
|
||||||
state.activeName = state.dbId + state.db + tableName;
|
state.activeName = state.dbId + state.db + tableName;
|
||||||
state.nowTableName = state.activeName;
|
state.nowTableName = state.activeName;
|
||||||
let tab = state.dataTabs[state.dbId + state.db +tableName];
|
let tab = state.dataTabs[state.dbId + state.db + tableName];
|
||||||
// 如果存在该表tab,则直接返回
|
// 如果存在该表tab,则直接返回
|
||||||
if (tab) {
|
if (tab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tab = {
|
tab = {
|
||||||
label: '`' + state.db+ '`.'+ tableName,
|
label: '`' + state.db + '`.' + tableName,
|
||||||
key : state.dbId + state.db +tableName,
|
key: state.dbId + state.db + tableName,
|
||||||
name: tableName,
|
name: tableName,
|
||||||
datas: [],
|
datas: [],
|
||||||
columnNames: [],
|
columnNames: [],
|
||||||
@@ -1100,7 +1119,7 @@ const changeTable = async (tableName: string, execSelectSql: boolean = true) =>
|
|||||||
db: state.db,
|
db: state.db,
|
||||||
};
|
};
|
||||||
tab.columnNames = await getColumnNames(tableName);
|
tab.columnNames = await getColumnNames(tableName);
|
||||||
state.dataTabs[state.dbId + state.db +tableName] = tab;
|
state.dataTabs[state.dbId + state.db + tableName] = tab;
|
||||||
|
|
||||||
await onRefresh(state.dbId, state.db, tableName);
|
await onRefresh(state.dbId, state.db, tableName);
|
||||||
};
|
};
|
||||||
@@ -1168,7 +1187,7 @@ const onCancelCondition = () => {
|
|||||||
state.conditionDialog.dataTab = null;
|
state.conditionDialog.dataTab = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRefresh = async (dbId:any, db: string, tableName: string) => {
|
const onRefresh = async (dbId: any, db: string, tableName: string) => {
|
||||||
const dataTab = state.dataTabs[state.dbId + state.db + tableName];
|
const dataTab = state.dataTabs[state.dbId + state.db + tableName];
|
||||||
// 查询条件置空
|
// 查询条件置空
|
||||||
dataTab.condition = '';
|
dataTab.condition = '';
|
||||||
@@ -1191,7 +1210,7 @@ const handlePageChange = async (dataTab: any) => {
|
|||||||
*/
|
*/
|
||||||
const selectByCondition = async (tableName: string, condition: string) => {
|
const selectByCondition = async (tableName: string, condition: string) => {
|
||||||
notEmpty(condition, '条件不能为空');
|
notEmpty(condition, '条件不能为空');
|
||||||
const dataTab = state.dataTabs[state.dbId + state.db +tableName];
|
const dataTab = state.dataTabs[state.dbId + state.db + tableName];
|
||||||
dataTab.pageNum = 1;
|
dataTab.pageNum = 1;
|
||||||
await setDataTabDatas(dataTab);
|
await setDataTabDatas(dataTab);
|
||||||
};
|
};
|
||||||
@@ -1278,10 +1297,10 @@ const changeSqlTemplate = (dbId: any, db: string) => {
|
|||||||
const getUserSql = (dbId: any, db: string, sql: string) => {
|
const getUserSql = (dbId: any, db: string, sql: string) => {
|
||||||
notBlank(dbId, '请先选择数据库');
|
notBlank(dbId, '请先选择数据库');
|
||||||
sql && setSqlEditorValue(dbId, db, sql) ||
|
sql && setSqlEditorValue(dbId, db, sql) ||
|
||||||
dbApi.getSql.request({ id: dbId, type: 1, name: state.sqlName[dbId+db], db: db }).then((res: any) => {
|
dbApi.getSql.request({ id: dbId, type: 1, name: state.sqlName[dbId + db], db: db }).then((res: any) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
setSqlEditorValue(dbId, db, res.sql);
|
setSqlEditorValue(dbId, db, res.sql);
|
||||||
state.sqlMap[dbId+db+state.sqlName[dbId+db]] = res.sql
|
state.sqlMap[dbId + db + state.sqlName[dbId + db]] = res.sql
|
||||||
} else {
|
} else {
|
||||||
setSqlEditorValue(dbId, db, '');
|
setSqlEditorValue(dbId, db, '');
|
||||||
}
|
}
|
||||||
@@ -1298,7 +1317,7 @@ const setSqlEditorValue = (dbId: any, db: string, value: string) => {
|
|||||||
*/
|
*/
|
||||||
const getSqlNames = (dbId: any, db: string) => {
|
const getSqlNames = (dbId: any, db: string) => {
|
||||||
!state.sqlNames[dbId + db] &&
|
!state.sqlNames[dbId + db] &&
|
||||||
dbApi.getSqlNames.request({id: dbId, db: db,})
|
dbApi.getSqlNames.request({ id: dbId, db: db, })
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
if (res && res.length > 0) {
|
if (res && res.length > 0) {
|
||||||
state.sqlNames[dbId + db] = res.map((r: any) => r.name);
|
state.sqlNames[dbId + db] = res.map((r: any) => r.name);
|
||||||
@@ -1315,7 +1334,7 @@ const saveSql = async (dbId: any, db: string) => {
|
|||||||
const sql = monacoEditor.getModel()?.getValue();
|
const sql = monacoEditor.getModel()?.getValue();
|
||||||
notBlank(sql, 'sql内容不能为空');
|
notBlank(sql, 'sql内容不能为空');
|
||||||
notBlank(state.dbId, '请先选择数据库实例');
|
notBlank(state.dbId, '请先选择数据库实例');
|
||||||
await dbApi.saveSql.request({ id: dbId, db: db, sql: sql, type: 1, name: state.sqlName[dbId+db] });
|
await dbApi.saveSql.request({ id: dbId, db: db, sql: sql, type: 1, name: state.sqlName[dbId + db] });
|
||||||
ElMessage.success('保存成功');
|
ElMessage.success('保存成功');
|
||||||
|
|
||||||
dbApi.getSqlNames
|
dbApi.getSqlNames
|
||||||
@@ -1325,19 +1344,19 @@ const saveSql = async (dbId: any, db: string) => {
|
|||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
state.sqlNames[dbId+db] = res.map((r: any) => r.name);
|
state.sqlNames[dbId + db] = res.map((r: any) => r.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteSql = async (dbId: any, db: string) => {
|
const deleteSql = async (dbId: any, db: string) => {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm(`确定删除【${state.sqlName[dbId+db]}】该SQL模板?`, '提示', {
|
await ElMessageBox.confirm(`确定删除【${state.sqlName[dbId + db]}】该SQL模板?`, '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
});
|
});
|
||||||
await dbApi.deleteDbSql.request({ id: dbId, db: db, name: state.sqlName[dbId+db]});
|
await dbApi.deleteDbSql.request({ id: dbId, db: db, name: state.sqlName[dbId + db] });
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
getSqlNames(dbId, db);
|
getSqlNames(dbId, db);
|
||||||
} catch (err) { }
|
} catch (err) { }
|
||||||
@@ -1354,7 +1373,7 @@ const onDataSelectionChange = (datas: []) => {
|
|||||||
/**
|
/**
|
||||||
* 执行删除数据事件
|
* 执行删除数据事件
|
||||||
*/
|
*/
|
||||||
const onDeleteData = async (dbId:any, db: string, tableName: string) => {
|
const onDeleteData = async (dbId: any, db: string, tableName: string) => {
|
||||||
const isQuery = isQueryTab();
|
const isQuery = isQueryTab();
|
||||||
const queryTab = state.queryTabs[state.activeName];
|
const queryTab = state.queryTabs[state.activeName];
|
||||||
const deleteDatas = isQuery ? queryTab.selectionDatas : state.dataTabs[state.activeName].selectionDatas;
|
const deleteDatas = isQuery ? queryTab.selectionDatas : state.dataTabs[state.activeName].selectionDatas;
|
||||||
@@ -1414,7 +1433,7 @@ const isQueryTab = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 监听单元格点击事件
|
// 监听单元格点击事件
|
||||||
const cellClick = (row: any, column: any, cell: any, event: Event, tabInfo: {dbId: number, db: string, tableName: string}) => {
|
const cellClick = (row: any, column: any, cell: any, event: Event, tabInfo: { dbId: number, db: string, tableName: string }) => {
|
||||||
const property = column.property;
|
const property = column.property;
|
||||||
// 如果当前操作的表名不存在 或者 当前列的property不存在(如多选框),则不允许修改当前单元格内容
|
// 如果当前操作的表名不存在 或者 当前列的property不存在(如多选框),则不允许修改当前单元格内容
|
||||||
if (!state.nowTableName || !property) {
|
if (!state.nowTableName || !property) {
|
||||||
@@ -1445,7 +1464,8 @@ const cellClick = (row: any, column: any, cell: any, event: Event, tabInfo: {dbI
|
|||||||
const primaryKeyValue = row[primaryKey.columnName];
|
const primaryKeyValue = row[primaryKey.columnName];
|
||||||
// 更新字段列信息
|
// 更新字段列信息
|
||||||
const updateColumn = await getColumn(tabInfo.tableName, property);
|
const updateColumn = await getColumn(tabInfo.tableName, property);
|
||||||
const newField = { div, row,
|
const newField = {
|
||||||
|
div, row,
|
||||||
fieldName: column.rawColumnKey,
|
fieldName: column.rawColumnKey,
|
||||||
fieldType: updateColumn.columnType,
|
fieldType: updateColumn.columnType,
|
||||||
oldValue: text,
|
oldValue: text,
|
||||||
@@ -1460,7 +1480,8 @@ const cellClick = (row: any, column: any, cell: any, event: Event, tabInfo: {dbI
|
|||||||
primaryKey: primaryKeyValue,
|
primaryKey: primaryKeyValue,
|
||||||
primaryKeyName: primaryKey.columnName,
|
primaryKeyName: primaryKey.columnName,
|
||||||
primaryKeyType: primaryKey.columnType,
|
primaryKeyType: primaryKey.columnType,
|
||||||
fields: [newField] }
|
fields: [newField]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
hasKey = true
|
hasKey = true
|
||||||
let hasField = primaryKeyFields[0].fields.some(a => {
|
let hasField = primaryKeyFields[0].fields.some(a => {
|
||||||
@@ -1523,7 +1544,7 @@ const cellClick = (row: any, column: any, cell: any, event: Event, tabInfo: {dbI
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitUpdateFields = (dbId:any, db: string, tableName: string) => {
|
const submitUpdateFields = (dbId: any, db: string, tableName: string) => {
|
||||||
let currentUpdatedFields: UpdateFieldsMeta[];
|
let currentUpdatedFields: UpdateFieldsMeta[];
|
||||||
let isQuery = false;
|
let isQuery = false;
|
||||||
if (isQueryTab()) {
|
if (isQueryTab()) {
|
||||||
@@ -1620,7 +1641,7 @@ const isNumber = (columnType: string) => {
|
|||||||
/**
|
/**
|
||||||
* 弹框提示是否执行sql
|
* 弹框提示是否执行sql
|
||||||
*/
|
*/
|
||||||
const promptExeSql = (dbId:any, db: string, sql: string, cancelFunc: any = null, successFunc: any = null) => {
|
const promptExeSql = (dbId: any, db: string, sql: string, cancelFunc: any = null, successFunc: any = null) => {
|
||||||
SqlExecBox({
|
SqlExecBox({
|
||||||
sql, dbId, db,
|
sql, dbId, db,
|
||||||
runSuccessCallback: successFunc,
|
runSuccessCallback: successFunc,
|
||||||
@@ -1629,12 +1650,12 @@ const promptExeSql = (dbId:any, db: string, sql: string, cancelFunc: any = null,
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 添加新数据行
|
// 添加新数据行
|
||||||
const addRow = async (dbId:any, db: string, tableName: string) => {
|
const addRow = async (dbId: any, db: string, tableName: string) => {
|
||||||
const columns = await getColumns(tableName);
|
const columns = await getColumns(tableName);
|
||||||
// key: 字段名,value: 字段名提示
|
// key: 字段名,value: 字段名提示
|
||||||
let obj: any = {};
|
let obj: any = {};
|
||||||
columns.forEach((item: any) => {
|
columns.forEach((item: any) => {
|
||||||
obj[`${item.columnName}`] = `'${item.columnComment||''} ${item.columnName}[${item.columnType}]${item.nullable == 'YES' ? '' : '[not null]'}'`;
|
obj[`${item.columnName}`] = `'${item.columnComment || ''} ${item.columnName}[${item.columnType}]${item.nullable == 'YES' ? '' : '[not null]'}'`;
|
||||||
});
|
});
|
||||||
let columnNames = Object.keys(obj).join(',');
|
let columnNames = Object.keys(obj).join(',');
|
||||||
let values = Object.values(obj).join(',');
|
let values = Object.values(obj).join(',');
|
||||||
@@ -1701,15 +1722,15 @@ const replaceSelection = (dbId: any, db: string, str: string, selection: any) =>
|
|||||||
|
|
||||||
// 加载实例数据
|
// 加载实例数据
|
||||||
const loadInstances = async () => {
|
const loadInstances = async () => {
|
||||||
const res = await dbApi.dbs.request({pageNum: 1, pageSize: 1000,})
|
const res = await dbApi.dbs.request({ pageNum: 1, pageSize: 1000, })
|
||||||
if(!res.total) return
|
if (!res.total) return
|
||||||
|
|
||||||
state.instances = {tags:{}, tree:{}, dbs:{}, tables:{}, sqls:{}} ; // 初始化变量
|
state.instances = { tags: {}, tree: {}, dbs: {}, tables: {}, sqls: {} }; // 初始化变量
|
||||||
for (const db of res.list) {
|
for (const db of res.list) {
|
||||||
let arr = state.instances.tree[db.tagId] || []
|
let arr = state.instances.tree[db.tagId] || []
|
||||||
const {tagId, tagPath} = db
|
const { tagId, tagPath } = db
|
||||||
// tags
|
// tags
|
||||||
state.instances.tags[db.tagId]={tagId, tagPath}
|
state.instances.tags[db.tagId] = { tagId, tagPath }
|
||||||
|
|
||||||
// tree
|
// tree
|
||||||
arr.push(db)
|
arr.push(db)
|
||||||
@@ -1724,14 +1745,14 @@ const loadInstances = async () => {
|
|||||||
// 加载实例对应的所有表名
|
// 加载实例对应的所有表名
|
||||||
const loadSchemaTables = async (inst: any, schema: string, fn: Function) => {
|
const loadSchemaTables = async (inst: any, schema: string, fn: Function) => {
|
||||||
changeSchema(inst, schema)
|
changeSchema(inst, schema)
|
||||||
let {id} = inst
|
let { id } = inst
|
||||||
let tables = state.instances.tables[id+schema];
|
let tables = state.instances.tables[id + schema];
|
||||||
if(!tables){
|
if (!tables) {
|
||||||
let tables = await dbApi.tableMetadata.request({ id, db: schema })
|
let tables = await dbApi.tableMetadata.request({ id, db: schema })
|
||||||
tables && tables.forEach((a:any)=>a.show=true)
|
tables && tables.forEach((a: any) => a.show = true)
|
||||||
state.instances.tables[id+schema] = tables;
|
state.instances.tables[id + schema] = tables;
|
||||||
}else {
|
} else {
|
||||||
tables.forEach((a:any)=>a.show=true)
|
tables.forEach((a: any) => a.show = true)
|
||||||
}
|
}
|
||||||
fn(state.instances.tables[id+schema])
|
fn(state.instances.tables[id+schema])
|
||||||
}
|
}
|
||||||
@@ -1757,9 +1778,9 @@ const loadTableData = async (inst: any, schema: string, tableName: string) => {
|
|||||||
|
|
||||||
// 新建查询panel
|
// 新建查询panel
|
||||||
const addQueryTab = async () => {
|
const addQueryTab = async () => {
|
||||||
let {dbId, db} = state
|
let { dbId, db } = state
|
||||||
|
|
||||||
if(!db){
|
if (!db) {
|
||||||
ElMessage.warning('请选择schema')
|
ElMessage.warning('请选择schema')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1783,20 +1804,20 @@ const addQueryTab = async () => {
|
|||||||
nowTableName: '', //当前表格数据操作的数据库表名,用于双击编辑表内容使用
|
nowTableName: '', //当前表格数据操作的数据库表名,用于双击编辑表内容使用
|
||||||
selectionDatas: [],
|
selectionDatas: [],
|
||||||
updatedFields: [] as UpdateFieldsMeta[],
|
updatedFields: [] as UpdateFieldsMeta[],
|
||||||
editorId: 'MonacoTextarea-'+id,
|
editorId: 'MonacoTextarea-' + id,
|
||||||
dbId:dbId,
|
dbId: dbId,
|
||||||
db:db
|
db: db
|
||||||
}
|
}
|
||||||
state.queryTabs[name]=queryTab
|
state.queryTabs[name] = queryTab
|
||||||
|
|
||||||
state.activeName = name;
|
state.activeName = name;
|
||||||
state.activeNameMap[name] = {dbId, db}
|
state.activeNameMap[name] = { dbId, db }
|
||||||
|
|
||||||
getSqlNames(dbId, db)
|
getSqlNames(dbId, db)
|
||||||
|
|
||||||
await nextTick(()=>{
|
await nextTick(() => {
|
||||||
loadSchemaMeta(dbId, db)
|
loadSchemaMeta(dbId, db)
|
||||||
setTimeout(()=>initMonacoEditor(queryTab), 500)
|
setTimeout(() => initMonacoEditor(queryTab), 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1833,9 +1854,11 @@ const addQueryTab = async () => {
|
|||||||
|
|
||||||
#data-exec {
|
#data-exec {
|
||||||
min-height: calc(100vh - 155px);
|
min-height: calc(100vh - 155px);
|
||||||
.el-tabs__header{
|
|
||||||
|
.el-tabs__header {
|
||||||
margin: 0 0 5px;
|
margin: 0 0 5px;
|
||||||
.el-tabs__item{
|
|
||||||
|
.el-tabs__item {
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,53 +6,54 @@
|
|||||||
<!-- 第一级:tag -->
|
<!-- 第一级:tag -->
|
||||||
<el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
|
<el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon><FolderOpened color="#e6a23c"/></el-icon>
|
<el-icon>
|
||||||
|
<FolderOpened color="#e6a23c" />
|
||||||
|
</el-icon>
|
||||||
<span>{{ tag.tagPath }}</span>
|
<span>{{ tag.tagPath }}</span>
|
||||||
</template>
|
</template>
|
||||||
<!-- 第二级:数据库实例 -->
|
<!-- 第二级:数据库实例 -->
|
||||||
<el-sub-menu v-for="inst in instances.tree[tag.tagId]"
|
<el-sub-menu v-for="inst in instances.tree[tag.tagId]" :index="'instance-' + inst.id"
|
||||||
:index="'instance-' + inst.id"
|
:key="'instance-' + inst.id" @click="changeInstance(inst, ()=>{})">
|
||||||
:key="'instance-' + inst.id"
|
|
||||||
@click="changeInstance(inst, ()=>{})"
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-popover
|
<el-popover placement="right-start" title="数据库实例信息" trigger="hover" :width="210">
|
||||||
placement="right-start"
|
|
||||||
title="数据库实例信息"
|
|
||||||
trigger="hover"
|
|
||||||
:width="210"
|
|
||||||
>
|
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<span> <el-icon><MostlyCloudy color="#409eff"/></el-icon>{{ inst.name }}</span>
|
<span> <el-icon>
|
||||||
|
<MostlyCloudy color="#409eff" />
|
||||||
|
</el-icon>{{ inst.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<el-form class="instances-pop-form" label-width="55px" :size="'small'">
|
<el-form class="instances-pop-form" label-width="55px" :size="'small'">
|
||||||
<el-form-item label="类型:">{{inst.type}}</el-form-item>
|
<el-form-item label="类型:">{{ inst.type }}</el-form-item>
|
||||||
<el-form-item label="链接:">{{inst.host}}:{{inst.port}}</el-form-item>
|
<el-form-item label="链接:">{{ inst.host }}:{{ inst.port }}</el-form-item>
|
||||||
<el-form-item label="用户:">{{inst.username}}</el-form-item>
|
<el-form-item label="用户:">{{ inst.username }}</el-form-item>
|
||||||
<el-form-item v-if="inst.remark" label="备注:">{{inst.remark}}</el-form-item>
|
<el-form-item v-if="inst.remark" label="备注:">{{
|
||||||
|
inst.remark
|
||||||
|
}}</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</template>
|
</template>
|
||||||
<!-- 第三级:数据库 -->
|
<!-- 第三级:数据库 -->
|
||||||
<el-sub-menu v-for="schema in instances.dbs[inst.id]"
|
<el-sub-menu v-for="schema in instances.dbs[inst.id]" :index="inst.id + schema"
|
||||||
:index="inst.id + schema"
|
:key="inst.id + schema" :class="state.nowSchema === (inst.id + schema) && 'checked'"
|
||||||
:key="inst.id + schema"
|
@click="changeSchema(inst, schema)">
|
||||||
:class="state.nowSchema === (inst.id+schema) && 'checked'"
|
|
||||||
@click="changeSchema(inst, schema)"
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon><Coin color="#67c23a"/></el-icon>
|
<el-icon>
|
||||||
|
<Coin color="#67c23a" />
|
||||||
|
</el-icon>
|
||||||
<span class="checked-schema">{{ schema }}</span>
|
<span class="checked-schema">{{ schema }}</span>
|
||||||
</template>
|
</template>
|
||||||
<!-- 第四级 01:表 -->
|
<!-- 第四级 01:表 -->
|
||||||
<el-sub-menu :index="inst.id + schema + '-table'" >
|
<el-sub-menu :index="inst.id + schema + '-table'">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div style="width: 100%" @click="loadTableNames(inst, schema, ()=>{})">
|
<div style="width: 100%" @click="loadTableNames(inst, schema, ()=>{})">
|
||||||
<el-icon><Calendar color="#409eff"/></el-icon>
|
<el-icon>
|
||||||
|
<Calendar color="#409eff"/>
|
||||||
|
</el-icon>
|
||||||
<span>表</span>
|
<span>表</span>
|
||||||
<el-icon v-show="state.loading[inst.id + schema]" class="is-loading"><Loading /></el-icon>
|
<el-icon v-show="state.loading[inst.id + schema]" class="is-loading">
|
||||||
|
<Loading />
|
||||||
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item :index="inst.id + schema + '-tableSearch'"
|
<el-menu-item :index="inst.id + schema + '-tableSearch'"
|
||||||
@@ -61,21 +62,25 @@
|
|||||||
|
|
||||||
<el-input size="small" placeholder="过滤表" clearable
|
<el-input size="small" placeholder="过滤表" clearable
|
||||||
@change="filterTableName(inst.id, schema)"
|
@change="filterTableName(inst.id, schema)"
|
||||||
@keyup="e => filterTableName(inst.id, schema, e)"
|
@keyup="(e: any) => filterTableName(inst.id, schema, e)"
|
||||||
v-model="state.filterParam[inst.id+schema]"/>
|
v-model="state.filterParam[inst.id + schema]" />
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
|
||||||
<template v-for="tb in instances.tables[inst.id+schema]" >
|
<template v-for="tb in instances.tables[inst.id + schema]">
|
||||||
<el-menu-item :index="inst.id + schema + tb.tableName"
|
<el-menu-item :index="inst.id + schema + tb.tableName"
|
||||||
:key="inst.id + schema + tb.tableName"
|
:key="inst.id + schema + tb.tableName" v-if="tb.show"
|
||||||
v-if="tb.show"
|
@click="loadTableData(inst, schema, tb.tableName)">
|
||||||
@click="loadTableData(inst, schema, tb.tableName)"
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<div style="width: 100%" >
|
<div style="width: 100%">
|
||||||
<el-icon><Calendar color="#409eff"/></el-icon>
|
<el-icon>
|
||||||
<span :title="tb.tableComment||''">{{tb.tableName}}</span>
|
<Calendar color="#409eff" />
|
||||||
|
</el-icon>
|
||||||
|
<el-tooltip v-if="tb.tableComment" effect="customized"
|
||||||
|
:content="tb.tableComment" placement="right">
|
||||||
|
{{ tb.tableName }}
|
||||||
|
</el-tooltip>
|
||||||
|
<span v-else>{{ tb.tableName }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
@@ -84,20 +89,22 @@
|
|||||||
<!-- 第四级 02:sql -->
|
<!-- 第四级 02:sql -->
|
||||||
<el-sub-menu :index="inst.id + schema + '-sql'">
|
<el-sub-menu :index="inst.id + schema + '-sql'">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon><List color="#f56c6c"/></el-icon>
|
<el-icon>
|
||||||
|
<List color="#f56c6c" />
|
||||||
|
</el-icon>
|
||||||
<span>sql</span>
|
<span>sql</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-for="sql in instances.sqls[inst.id+schema]" >
|
<template v-for="sql in instances.sqls[inst.id + schema]">
|
||||||
<el-menu-item :index="inst.id + schema + sql.name"
|
<el-menu-item :index="inst.id + schema + sql.name"
|
||||||
:key="inst.id + schema + sql.name"
|
:key="inst.id + schema + sql.name" v-if="sql.show"
|
||||||
v-if="sql.show"
|
@click="loadSql(inst, schema, sql.name)">
|
||||||
@click="loadSql(inst, schema, sql.name)"
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<div style="width: 100%" >
|
<div style="width: 100%">
|
||||||
<el-icon><Calendar color="#409eff"/></el-icon>
|
<el-icon>
|
||||||
<span>{{sql.name}}</span>
|
<Calendar color="#409eff" />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ sql.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
@@ -125,9 +132,9 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['initLoadInstances','changeInstance','loadTableNames','loadTableData','changeSchema'])
|
const emits = defineEmits(['initLoadInstances', 'changeInstance', 'loadTableNames', 'loadTableData', 'changeSchema'])
|
||||||
|
|
||||||
onBeforeMount(async ()=>{
|
onBeforeMount(async () => {
|
||||||
await initLoadInstances()
|
await initLoadInstances()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -159,7 +166,7 @@ const changeInstance = (inst : any, fn: Function) => {
|
|||||||
* @param inst 选中的实例对象
|
* @param inst 选中的实例对象
|
||||||
* @param schema 选中的数据库schema
|
* @param schema 选中的数据库schema
|
||||||
*/
|
*/
|
||||||
const changeSchema = (inst : any, schema: string) => {
|
const changeSchema = (inst: any, schema: string) => {
|
||||||
state.nowSchema = inst.id + schema
|
state.nowSchema = inst.id + schema
|
||||||
emits('changeSchema', inst, schema)
|
emits('changeSchema', inst, schema)
|
||||||
}
|
}
|
||||||
@@ -170,9 +177,9 @@ const changeSchema = (inst : any, schema: string) => {
|
|||||||
* @param fn 加载表集合后的回调函数,参数:res 表集合
|
* @param fn 加载表集合后的回调函数,参数:res 表集合
|
||||||
*/
|
*/
|
||||||
const loadTableNames = async (inst: any, schema: string, fn: Function) => {
|
const loadTableNames = async (inst: any, schema: string, fn: Function) => {
|
||||||
state.loading[inst.id+schema] = true
|
state.loading[inst.id + schema] = true
|
||||||
await emits('loadTableNames', inst, schema, (res: any[])=>{
|
await emits('loadTableNames', inst, schema, (res: any[])=>{
|
||||||
state.loading[inst.id+schema] = false
|
state.loading[inst.id + schema] = false
|
||||||
fn && fn(res)
|
fn && fn(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -187,14 +194,14 @@ const loadTableData = (inst: any, schema: string, tableName: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filterTableName = (instId: number, schema: string, event?: any) => {
|
const filterTableName = (instId: number, schema: string, event?: any) => {
|
||||||
if(event){
|
if (event) {
|
||||||
state.filterParam[instId+schema] = event.target.value
|
state.filterParam[instId + schema] = event.target.value
|
||||||
}
|
}
|
||||||
let param = state.filterParam[instId+schema] as string
|
let param = state.filterParam[instId + schema] as string
|
||||||
param = param?.replace('/','\/')
|
param = param?.replace('/', '\/')
|
||||||
const key = instId + schema;
|
const key = instId + schema;
|
||||||
props.instances.tables[key].forEach((a:any) =>{
|
props.instances.tables[key].forEach((a: any) => {
|
||||||
a.show = param?eval('/'+param.split('').join('[_\w]*')+'[_\w]*/ig').test(a.tableName):true
|
a.show = param ? eval('/' + param.split('').join('[_\w]*') + '[_\w]*/ig').test(a.tableName) : true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,40 +242,47 @@ watch(()=>store.state.sqlExecInfo.dbOptInfo, async newValue => {
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.instances-box {
|
.instances-box {
|
||||||
.el-menu{
|
.el-menu {
|
||||||
width: 275px;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.el-sub-menu{
|
|
||||||
.checked{
|
.el-sub-menu {
|
||||||
.checked-schema{
|
.checked {
|
||||||
|
.checked-schema {
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-sub-menu__title{
|
|
||||||
|
.el-sub-menu__title {
|
||||||
padding-left: 0 !important;
|
padding-left: 0 !important;
|
||||||
height: 30px !important;
|
height: 30px !important;
|
||||||
line-height: 30px !important;
|
line-height: 30px !important;
|
||||||
}
|
}
|
||||||
.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title{
|
|
||||||
|
.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
.el-menu-item{
|
|
||||||
|
.el-menu-item {
|
||||||
padding-left: 0 !important;
|
padding-left: 0 !important;
|
||||||
height: 20px !important;
|
height: 20px !important;
|
||||||
line-height: 20px !important;
|
line-height: 20px !important;
|
||||||
}
|
}
|
||||||
.el-icon{
|
|
||||||
|
.el-icon {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.el-sub-menu__icon-arrow{
|
|
||||||
top:inherit;
|
.el-sub-menu__icon-arrow {
|
||||||
|
top: inherit;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.instances-pop-form{
|
|
||||||
.el-form-item{
|
.instances-pop-form {
|
||||||
|
.el-form-item {
|
||||||
margin-bottom: unset;
|
margin-bottom: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,16 @@
|
|||||||
<el-col :span="24" :style="{
|
<el-col :span="24" :style="{
|
||||||
maxHeight: state.instanceMenuMaxHeight,
|
maxHeight: state.instanceMenuMaxHeight,
|
||||||
height: state.instanceMenuMaxHeight,
|
height: state.instanceMenuMaxHeight,
|
||||||
overflow:'auto'
|
overflow: 'auto'
|
||||||
}" class="el-scrollbar flex-auto">
|
}" class="el-scrollbar flex-auto">
|
||||||
|
|
||||||
<el-menu background-color="transparent" ref="menuRef">
|
<el-menu background-color="transparent" ref="menuRef">
|
||||||
<!-- 第一级:tag -->
|
<!-- 第一级:tag -->
|
||||||
<el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
|
<el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon><FolderOpened color="#e6a23c"/></el-icon>
|
<el-icon>
|
||||||
|
<FolderOpened color="#e6a23c" />
|
||||||
|
</el-icon>
|
||||||
<span>{{ tag.tagPath }}</span>
|
<span>{{ tag.tagPath }}</span>
|
||||||
</template>
|
</template>
|
||||||
<!-- 第二级:数据库实例 -->
|
<!-- 第二级:数据库实例 -->
|
||||||
@@ -21,44 +23,46 @@
|
|||||||
@click.prevent="changeInstance(inst, ()=>{})"
|
@click.prevent="changeInstance(inst, ()=>{})"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-popover
|
<el-popover placement="right-start" title="mongo数据库实例信息" trigger="hover" :width="210">
|
||||||
placement="right-start"
|
|
||||||
title="mongo数据库实例信息"
|
|
||||||
trigger="hover"
|
|
||||||
:width="210"
|
|
||||||
>
|
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<span> <el-icon><MostlyCloudy color="#409eff"/></el-icon>{{ inst.name }}</span>
|
<span> <el-icon>
|
||||||
|
<MostlyCloudy color="#409eff" />
|
||||||
|
</el-icon>{{ inst.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<el-form class="instances-pop-form" label-width="55px" :size="'small'">
|
<el-form class="instances-pop-form" label-width="55px" :size="'small'">
|
||||||
<el-form-item label="名称:">{{inst.name}}</el-form-item>
|
<el-form-item label="名称:">{{ inst.name }}</el-form-item>
|
||||||
<el-form-item label="链接:">{{inst.uri}}</el-form-item>
|
<el-form-item label="链接:">{{ inst.uri }}</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</template>
|
</template>
|
||||||
<!-- 第三级:数据库 -->
|
<!-- 第三级:数据库 -->
|
||||||
<el-sub-menu v-for="db in instances.dbs[inst.id]"
|
<el-sub-menu v-for="db in instances.dbs[inst.id]" :index="inst.id + db.Name"
|
||||||
:index="inst.id + db.Name"
|
:key="inst.id + db.Name" :class="state.nowSchema === (inst.id + db.Name) && 'checked'"
|
||||||
:key="inst.id + db.Name"
|
@click.prevent="changeSchema(inst, db.Name)">
|
||||||
:class="state.nowSchema === (inst.id+db.Name) && 'checked'"
|
|
||||||
@click.prevent="changeSchema(inst, db.Name)"
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon><Coin color="#67c23a"/></el-icon>
|
<el-icon>
|
||||||
|
<Coin color="#67c23a" />
|
||||||
|
</el-icon>
|
||||||
<span class="checked-schema">
|
<span class="checked-schema">
|
||||||
{{ db.Name }}
|
{{ db.Name }}
|
||||||
<span style="color: #8492a6;font-size: 13px">[{{formatByteSize(db.SizeOnDisk)}}]</span>
|
<span style="color: #8492a6;font-size: 13px">[{{
|
||||||
|
formatByteSize(db.SizeOnDisk)
|
||||||
|
}}]</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<!-- 第四级 01:表 -->
|
<!-- 第四级 01:表 -->
|
||||||
<el-sub-menu :index="inst.id + db.Name + '-table'" >
|
<el-sub-menu :index="inst.id + db.Name + '-table'">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div style="width: 100%" @click="loadTableNames(inst, db.Name, ()=>{})">
|
<div style="width: 100%" @click="loadTableNames(inst, db.Name, ()=>{})">
|
||||||
<el-icon><Calendar color="#409eff"/></el-icon>
|
<el-icon>
|
||||||
|
<Calendar color="#409eff"/>
|
||||||
|
</el-icon>
|
||||||
<span>集合</span>
|
<span>集合</span>
|
||||||
<el-icon v-show="state.loading[inst.id + db.Name]" class="is-loading"><Loading /></el-icon>
|
<el-icon v-show="state.loading[inst.id + db.Name]" class="is-loading">
|
||||||
|
<Loading />
|
||||||
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item :index="inst.id + db.Name + '-tableSearch'"
|
<el-menu-item :index="inst.id + db.Name + '-tableSearch'"
|
||||||
@@ -67,21 +71,21 @@
|
|||||||
|
|
||||||
<el-input size="small" placeholder="过滤" clearable
|
<el-input size="small" placeholder="过滤" clearable
|
||||||
@change="filterTableName(inst.id, db.Name)"
|
@change="filterTableName(inst.id, db.Name)"
|
||||||
@keyup="e => filterTableName(inst.id, db.Name, e)"
|
@keyup="(e: any) => filterTableName(inst.id, db.Name, e)"
|
||||||
v-model="state.filterParam[inst.id+db.Name]"/>
|
v-model="state.filterParam[inst.id + db.Name]" />
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
|
||||||
<template v-for="tb in instances.tables[inst.id+db.Name]" >
|
<template v-for="tb in instances.tables[inst.id + db.Name]">
|
||||||
<el-menu-item :index="inst.id + db.Name + tb.tableName"
|
<el-menu-item :index="inst.id + db.Name + tb.tableName"
|
||||||
:key="inst.id + db.Name + tb.tableName"
|
:key="inst.id + db.Name + tb.tableName" v-if="tb.show"
|
||||||
v-if="tb.show"
|
@click="loadTableData(inst, db.Name, tb.tableName)">
|
||||||
@click="loadTableData(inst, db.Name, tb.tableName)"
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<div style="width: 100%" >
|
<div style="width: 100%">
|
||||||
<el-icon><Calendar color="#409eff"/></el-icon>
|
<el-icon>
|
||||||
<span :title="tb.tableComment||''">{{tb.tableName}}</span>
|
<Calendar color="#409eff" />
|
||||||
|
</el-icon>
|
||||||
|
<span :title="tb.tableComment || ''">{{ tb.tableName }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
@@ -98,7 +102,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {nextTick, onBeforeMount, onMounted, reactive, ref, Ref, watch} from 'vue';
|
import {nextTick, onBeforeMount, onMounted, reactive, ref, Ref, watch} from 'vue';
|
||||||
import {formatByteSize} from '@/common/utils/format';
|
import { formatByteSize } from '@/common/utils/format';
|
||||||
import {store} from '@/store';
|
import {store} from '@/store';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -107,9 +111,9 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['initLoadInstances','changeInstance','loadTableNames','loadTableData','changeSchema'])
|
const emits = defineEmits(['initLoadInstances', 'changeInstance', 'loadTableNames', 'loadTableData', 'changeSchema'])
|
||||||
|
|
||||||
onBeforeMount(async ()=>{
|
onBeforeMount(async () => {
|
||||||
await initLoadInstances()
|
await initLoadInstances()
|
||||||
setHeight()
|
setHeight()
|
||||||
})
|
})
|
||||||
@@ -148,7 +152,7 @@ const changeInstance = (inst : any, fn: Function) => {
|
|||||||
* @param inst 选中的实例对象
|
* @param inst 选中的实例对象
|
||||||
* @param schema 选中的数据库schema
|
* @param schema 选中的数据库schema
|
||||||
*/
|
*/
|
||||||
const changeSchema = (inst : any, schema: string) => {
|
const changeSchema = (inst: any, schema: string) => {
|
||||||
state.nowSchema = inst.id + schema
|
state.nowSchema = inst.id + schema
|
||||||
emits('changeSchema', inst, schema)
|
emits('changeSchema', inst, schema)
|
||||||
}
|
}
|
||||||
@@ -159,9 +163,9 @@ const changeSchema = (inst : any, schema: string) => {
|
|||||||
* @param schema database名
|
* @param schema database名
|
||||||
*/
|
*/
|
||||||
const loadTableNames = async (inst: any, schema: string, fn: Function) => {
|
const loadTableNames = async (inst: any, schema: string, fn: Function) => {
|
||||||
state.loading[inst.id+schema] = true
|
state.loading[inst.id + schema] = true
|
||||||
await emits('loadTableNames', inst, schema, (res: any)=>{
|
await emits('loadTableNames', inst, schema, (res: any)=>{
|
||||||
state.loading[inst.id+schema] = false
|
state.loading[inst.id + schema] = false
|
||||||
fn && fn(res)
|
fn && fn(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -176,14 +180,14 @@ const loadTableData = (inst: any, schema: string, tableName: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filterTableName = (instId: number, schema: string, event?: any) => {
|
const filterTableName = (instId: number, schema: string, event?: any) => {
|
||||||
if(event){
|
if (event) {
|
||||||
state.filterParam[instId+schema] = event.target.value
|
state.filterParam[instId + schema] = event.target.value
|
||||||
}
|
}
|
||||||
let param = state.filterParam[instId+schema] as string
|
let param = state.filterParam[instId + schema] as string
|
||||||
param = param?.replace('/','\/')
|
param = param?.replace('/', '\/')
|
||||||
const key = instId + schema;
|
const key = instId + schema;
|
||||||
props.instances.tables[key].forEach((a:any) =>{
|
props.instances.tables[key].forEach((a: any) => {
|
||||||
a.show = param?eval('/'+param.split('').join('[_\w]*')+'[_\w]*/ig').test(a.tableName):true
|
a.show = param ? eval('/' + param.split('').join('[_\w]*') + '[_\w]*/ig').test(a.tableName) : true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,40 +227,47 @@ watch(()=>store.state.mongoDbOptInfo.dbOptInfo, async newValue => {
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.instances-box {
|
.instances-box {
|
||||||
.el-menu{
|
.el-menu {
|
||||||
width: 275px;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.el-sub-menu{
|
|
||||||
.checked{
|
.el-sub-menu {
|
||||||
.checked-schema{
|
.checked {
|
||||||
|
.checked-schema {
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-sub-menu__title{
|
|
||||||
|
.el-sub-menu__title {
|
||||||
padding-left: 0 !important;
|
padding-left: 0 !important;
|
||||||
height: 30px !important;
|
height: 30px !important;
|
||||||
line-height: 30px !important;
|
line-height: 30px !important;
|
||||||
}
|
}
|
||||||
.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title{
|
|
||||||
|
.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
.el-menu-item{
|
|
||||||
|
.el-menu-item {
|
||||||
padding-left: 0 !important;
|
padding-left: 0 !important;
|
||||||
height: 20px !important;
|
height: 20px !important;
|
||||||
line-height: 20px !important;
|
line-height: 20px !important;
|
||||||
}
|
}
|
||||||
.el-icon{
|
|
||||||
|
.el-icon {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.el-sub-menu__icon-arrow{
|
|
||||||
top:inherit;
|
.el-sub-menu__icon-arrow {
|
||||||
|
top: inherit;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.instances-pop-form{
|
|
||||||
.el-form-item{
|
.instances-pop-form {
|
||||||
|
.el-form-item {
|
||||||
margin-bottom: unset;
|
margin-bottom: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ const cancel = () => {
|
|||||||
|
|
||||||
watch(props, async (newValue: any) => {
|
watch(props, async (newValue: any) => {
|
||||||
state.dialogVisible = newValue.visible;
|
state.dialogVisible = newValue.visible;
|
||||||
state.key = newValue.key;
|
|
||||||
state.redisId = newValue.redisId;
|
state.redisId = newValue.redisId;
|
||||||
state.db = newValue.db;
|
state.db = newValue.db;
|
||||||
state.key = newValue.keyInfo;
|
state.key = newValue.keyInfo;
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ const cancel = () => {
|
|||||||
|
|
||||||
watch(props, async (newValue: any) => {
|
watch(props, async (newValue: any) => {
|
||||||
state.dialogVisible = newValue.visible;
|
state.dialogVisible = newValue.visible;
|
||||||
state.key = newValue.key;
|
|
||||||
state.redisId = newValue.redisId;
|
state.redisId = newValue.redisId;
|
||||||
state.db = newValue.db;
|
state.db = newValue.db;
|
||||||
state.key = newValue.keyInfo;
|
state.key = newValue.keyInfo;
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ watch(
|
|||||||
|
|
||||||
watch(props, async (newValue: any) => {
|
watch(props, async (newValue: any) => {
|
||||||
state.dialogVisible = newValue.visible;
|
state.dialogVisible = newValue.visible;
|
||||||
state.key = newValue.key;
|
|
||||||
state.redisId = newValue.redisId;
|
state.redisId = newValue.redisId;
|
||||||
state.db = newValue.db;
|
state.db = newValue.db;
|
||||||
state.key = newValue.keyInfo;
|
state.key = newValue.keyInfo;
|
||||||
|
|||||||
@@ -772,10 +772,10 @@ echarts@^5.4.0:
|
|||||||
tslib "2.3.0"
|
tslib "2.3.0"
|
||||||
zrender "5.4.0"
|
zrender "5.4.0"
|
||||||
|
|
||||||
element-plus@^2.2.26:
|
element-plus@^2.2.29:
|
||||||
version "2.2.26"
|
version "2.2.29"
|
||||||
resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.2.26.tgz#5e46aa5d8127786bb158713957f8a253b35bf019"
|
resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.2.29.tgz#7dd72f9cafdc102ae3f9e4efe612e403ef713a74"
|
||||||
integrity sha512-O/rdY5m9DkclpVg8r3GynyqCunm7MxSR142xSsjrZA77bi7bcwA3SIy6SPEDqHi5R4KqgkGYgKSp4Q4e3irbYg==
|
integrity sha512-g4dcrURrKkR5uUX8n5RVnnqGnimoki9HfqS4yHHG6XwCHBkZGozdq4x+478BzeWUe31h++BO+7dakSx4VnM8RQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ctrl/tinycolor" "^3.4.1"
|
"@ctrl/tinycolor" "^3.4.1"
|
||||||
"@element-plus/icons-vue" "^2.0.6"
|
"@element-plus/icons-vue" "^2.0.6"
|
||||||
@@ -800,7 +800,7 @@ enquirer@^2.3.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ansi-colors "^4.1.1"
|
ansi-colors "^4.1.1"
|
||||||
|
|
||||||
esbuild@^0.16.3:
|
esbuild@^0.16.14:
|
||||||
version "0.16.17"
|
version "0.16.17"
|
||||||
resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259"
|
resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259"
|
||||||
integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==
|
integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==
|
||||||
@@ -1451,7 +1451,7 @@ postcss@^8.1.10:
|
|||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
source-map-js "^1.0.1"
|
source-map-js "^1.0.1"
|
||||||
|
|
||||||
postcss@^8.4.20:
|
postcss@^8.4.21:
|
||||||
version "8.4.21"
|
version "8.4.21"
|
||||||
resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
|
resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
|
||||||
integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
|
integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
|
||||||
@@ -1533,10 +1533,10 @@ rimraf@^3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
glob "^7.1.3"
|
glob "^7.1.3"
|
||||||
|
|
||||||
rollup@^3.7.0:
|
rollup@^3.10.0:
|
||||||
version "3.10.0"
|
version "3.12.1"
|
||||||
resolved "https://registry.npmmirror.com/rollup/-/rollup-3.10.0.tgz#6eb19196d8b3b375ca651cb78261faac48e24cd6"
|
resolved "https://registry.npmmirror.com/rollup/-/rollup-3.12.1.tgz#2975b97713e4af98c15e7024b88292d7fddb3853"
|
||||||
integrity sha512-JmRYz44NjC1MjVF2VKxc0M1a97vn+cDxeqWmnwyAF4FvpjK8YFdHpaqvQB+3IxCvX05vJxKZkoMDU8TShhmJVA==
|
integrity sha512-t9elERrz2i4UU9z7AwISj3CQcXP39cWxgRWLdf4Tm6aKm1eYrqHIgjzXBgb67GNY1sZckTFFi0oMozh3/S++Ig==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
@@ -1547,18 +1547,18 @@ run-parallel@^1.1.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask "^1.2.2"
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
sass-loader@^12.4.0:
|
sass-loader@^13.2.0:
|
||||||
version "12.4.0"
|
version "13.2.0"
|
||||||
resolved "https://registry.npmmirror.com/sass-loader/download/sass-loader-12.4.0.tgz"
|
resolved "https://registry.npmmirror.com/sass-loader/-/sass-loader-13.2.0.tgz#80195050f58c9aac63b792fa52acb6f5e0f6bdc3"
|
||||||
integrity sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==
|
integrity sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==
|
||||||
dependencies:
|
dependencies:
|
||||||
klona "^2.0.4"
|
klona "^2.0.4"
|
||||||
neo-async "^2.6.2"
|
neo-async "^2.6.2"
|
||||||
|
|
||||||
sass@^1.45.1:
|
sass@^1.58.0:
|
||||||
version "1.48.0"
|
version "1.58.0"
|
||||||
resolved "https://registry.npmmirror.com/sass/download/sass-1.48.0.tgz"
|
resolved "https://registry.npmmirror.com/sass/-/sass-1.58.0.tgz#ee8aea3ad5ea5c485c26b3096e2df6087d0bb1cc"
|
||||||
integrity sha512-hQi5g4DcfjcipotoHZ80l7GNJHGqQS5LwMBjVYB/TaT0vcSSpbgM8Ad7cgfsB2M0MinbkEQQPO9+sjjSiwxqmw==
|
integrity sha512-PiMJcP33DdKtZ/1jSjjqVIKihoDc6yWmYr9K/4r3fVVIEDAluD0q7XZiRKrNJcPK3qkLRF/79DND1H5q1LBjgg==
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar ">=3.0.0 <4.0.0"
|
chokidar ">=3.0.0 <4.0.0"
|
||||||
immutable "^4.0.0"
|
immutable "^4.0.0"
|
||||||
@@ -1724,15 +1724,15 @@ v8-compile-cache@^2.0.3:
|
|||||||
resolved "https://registry.nlark.com/v8-compile-cache/download/v8-compile-cache-2.3.0.tgz"
|
resolved "https://registry.nlark.com/v8-compile-cache/download/v8-compile-cache-2.3.0.tgz"
|
||||||
integrity sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=
|
integrity sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=
|
||||||
|
|
||||||
vite@^4.0.4:
|
vite@^4.1.1:
|
||||||
version "4.0.4"
|
version "4.1.1"
|
||||||
resolved "https://registry.npmmirror.com/vite/-/vite-4.0.4.tgz#4612ce0b47bbb233a887a54a4ae0c6e240a0da31"
|
resolved "https://registry.npmmirror.com/vite/-/vite-4.1.1.tgz#3b18b81a4e85ce3df5cbdbf4c687d93ebf402e6b"
|
||||||
integrity sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==
|
integrity sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.16.3"
|
esbuild "^0.16.14"
|
||||||
postcss "^8.4.20"
|
postcss "^8.4.21"
|
||||||
resolve "^1.22.1"
|
resolve "^1.22.1"
|
||||||
rollup "^3.7.0"
|
rollup "^3.10.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ mysql:
|
|||||||
host: localhost:3306
|
host: localhost:3306
|
||||||
username: root
|
username: root
|
||||||
password: 111049
|
password: 111049
|
||||||
db-name: mayfly-go
|
db-name: mayfly_go
|
||||||
config: charset=utf8&loc=Local&parseTime=true
|
config: charset=utf8&loc=Local&parseTime=true
|
||||||
max-idle-conns: 5
|
max-idle-conns: 5
|
||||||
# 若同时部署多台机器,则需要配置redis信息用于缓存权限码、验证码、公私钥等
|
# 若同时部署多台机器,则需要配置redis信息用于缓存权限码、验证码、公私钥等
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module mayfly-go
|
module mayfly-go
|
||||||
|
|
||||||
go 1.19
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.8.2
|
github.com/gin-gonic/gin v1.8.2
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ func InitRouter() *gin.Engine {
|
|||||||
|
|
||||||
sys_router.Init(api)
|
sys_router.Init(api)
|
||||||
|
|
||||||
// project_router.Init(api)
|
|
||||||
tag_router.Init(api)
|
tag_router.Init(api)
|
||||||
machine_router.Init(api)
|
machine_router.Init(api)
|
||||||
db_router.Init(api)
|
db_router.Init(api)
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ func valueConvert(data []byte, colType *sql.ColumnType) interface{} {
|
|||||||
return intV
|
return intV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.Contains(colScanType, "float") {
|
if strings.Contains(colScanType, "float") || strings.Contains(colDatabaseTypeName, "decimal") {
|
||||||
floatV, _ := strconv.ParseFloat(stringV, 64)
|
floatV, _ := strconv.ParseFloat(stringV, 64)
|
||||||
return floatV
|
return floatV
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package starter
|
package starter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"mayfly-go/pkg/config"
|
"mayfly-go/pkg/config"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/global"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -30,10 +33,20 @@ func gormMysql() *gorm.DB {
|
|||||||
SkipInitializeWithVersion: false, // 根据版本自动配置
|
SkipInitializeWithVersion: false, // 根据版本自动配置
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gormLogger := logger.New(
|
||||||
|
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
|
||||||
|
logger.Config{
|
||||||
|
SlowThreshold: time.Second, // 慢 SQL 阈值
|
||||||
|
LogLevel: logger.Error, // 日志级别, 改为logger.Info即可显示sql语句
|
||||||
|
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
|
||||||
|
Colorful: true, // 禁用彩色打印
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
ormConfig := &gorm.Config{NamingStrategy: schema.NamingStrategy{
|
ormConfig := &gorm.Config{NamingStrategy: schema.NamingStrategy{
|
||||||
TablePrefix: "t_",
|
TablePrefix: "t_",
|
||||||
SingularTable: true,
|
SingularTable: true,
|
||||||
}, Logger: logger.Default.LogMode(logger.Error)} // 改为logger.Info即可显示sql语句
|
}, Logger: gormLogger}
|
||||||
|
|
||||||
if db, err := gorm.Open(mysql.New(mysqlConfig), ormConfig); err != nil {
|
if db, err := gorm.Open(mysql.New(mysqlConfig), ormConfig); err != nil {
|
||||||
global.Log.Panicf("连接mysql失败! [%s]", err.Error())
|
global.Log.Panicf("连接mysql失败! [%s]", err.Error())
|
||||||
|
|||||||
Reference in New Issue
Block a user