diff --git a/mayfly_go_web/src/common/config.ts b/mayfly_go_web/src/common/config.ts index 8e13d364..df3d449d 100644 --- a/mayfly_go_web/src/common/config.ts +++ b/mayfly_go_web/src/common/config.ts @@ -3,6 +3,10 @@ function getBaseApiUrl() { if (path == '/') { return window.location.host; } + if (path.endsWith('/')) { + // 去除最后一个/ + return window.location.host + path.replace(/\/$/, ''); + } return window.location.host + path; } diff --git a/mayfly_go_web/src/components/terminal/TerminalDialog.vue b/mayfly_go_web/src/components/terminal/TerminalDialog.vue index 185d2674..730c8465 100644 --- a/mayfly_go_web/src/components/terminal/TerminalDialog.vue +++ b/mayfly_go_web/src/components/terminal/TerminalDialog.vue @@ -78,7 +78,7 @@ size="small" @click="maximize(minimizeTerminal.terminalId)" > - + {{ minimizeTerminal.title }} diff --git a/mayfly_go_web/src/views/ops/component/TagInfo.vue b/mayfly_go_web/src/views/ops/component/TagInfo.vue index 3297671b..f10f87c9 100644 --- a/mayfly_go_web/src/views/ops/component/TagInfo.vue +++ b/mayfly_go_web/src/views/ops/component/TagInfo.vue @@ -7,7 +7,7 @@ - + {{ v.name }} / diff --git a/mayfly_go_web/src/views/ops/component/tag.ts b/mayfly_go_web/src/views/ops/component/tag.ts index c8a5e9ab..0925d401 100644 --- a/mayfly_go_web/src/views/ops/component/tag.ts +++ b/mayfly_go_web/src/views/ops/component/tag.ts @@ -24,6 +24,8 @@ export class TagTreeNode { */ params: any; + icon: any; + static TagPath = -1; constructor(key: any, label: string, type?: NodeType) { @@ -42,6 +44,11 @@ export class TagTreeNode { return this; } + withIcon(icon: any) { + this.icon = icon; + return this; + } + /** * 加载子节点,使用节点类型的loadNodesFunc去加载子节点 * @returns 子节点信息 diff --git a/mayfly_go_web/src/views/ops/db/DbList.vue b/mayfly_go_web/src/views/ops/db/DbList.vue index 4d19fbeb..2da7f494 100644 --- a/mayfly_go_web/src/views/ops/db/DbList.vue +++ b/mayfly_go_web/src/views/ops/db/DbList.vue @@ -57,34 +57,14 @@ - - - - @@ -190,7 +166,6 @@ import { dbApi } from './api'; import config from '@/common/config'; import { joinClientParams } from '@/common/request'; import { isTrue } from '@/common/assert'; -import { Search as SearchIcon } from '@element-plus/icons-vue'; import { dateFormat } from '@/common/utils/date'; import TagInfo from '../component/TagInfo.vue'; import PageTable from '@/components/pagetable/PageTable.vue'; @@ -199,7 +174,6 @@ import { hasPerms } from '@/components/auth/auth'; import DbSqlExecLog from './DbSqlExecLog.vue'; const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue')); -const DbTableList = defineAsyncComponent(() => import('./table/DbTableList.vue')); const perms = { base: 'db', @@ -254,13 +228,6 @@ const state = reactive({ instanceId: 0, }, }, - showDumpInfo: false, - dumpInfo: { - id: 0, - db: '', - type: 3, - tables: [], - }, // sql执行记录弹框 sqlExecLogDialog: { title: '', @@ -268,10 +235,6 @@ const state = reactive({ dbs: [], dbId: 0, }, - chooseTableName: '', - tableInfoDialog: { - visible: false, - }, exportDialog: { visible: false, dbId: 0, @@ -293,8 +256,7 @@ const state = reactive({ }, }); -const { dbId, db, tags, selectionData, query, datas, total, infoDialog, sqlExecLogDialog, tableInfoDialog, exportDialog, dbEditDialog, filterDb } = - toRefs(state); +const { db, tags, selectionData, query, datas, total, infoDialog, sqlExecLogDialog, exportDialog, dbEditDialog } = toRefs(state); onMounted(async () => { if (Object.keys(actionBtns).length > 0) { @@ -449,36 +411,6 @@ const dumpDbs = () => { a.click(); state.exportDialog.visible = false; }; - -const showTableInfo = async (row: any, db: string) => { - state.dbId = row.id; - state.row = row; - state.db = db; - state.tableInfoDialog.visible = true; -}; - -const closeTableInfo = () => { - state.showDumpInfo = false; - state.tableInfoDialog.visible = false; -}; - -// 点击查看时初始化数据 -const selectDb = (row: any) => { - state.filterDb.param = ''; - state.filterDb.cache = row; - state.filterDb.list = row; -}; - -// 输入字符过滤schema -const filterSchema = () => { - if (state.filterDb.param) { - state.filterDb.list = state.filterDb.cache.filter((a) => { - return String(a).toLowerCase().indexOf(state.filterDb.param) > -1; - }); - } else { - state.filterDb.list = state.filterDb.cache; - } -}; diff --git a/mayfly_go_web/src/views/ops/db/api.ts b/mayfly_go_web/src/views/ops/db/api.ts index aa62e3b9..52e81b6b 100644 --- a/mayfly_go_web/src/views/ops/db/api.ts +++ b/mayfly_go_web/src/views/ops/db/api.ts @@ -11,6 +11,7 @@ export const dbApi = { tableIndex: Api.newGet('/dbs/{id}/t-index'), tableDdl: Api.newGet('/dbs/{id}/t-create-ddl'), columnMetadata: Api.newGet('/dbs/{id}/c-metadata'), + pgSchemas: Api.newGet('/dbs/{id}/pg/schemas'), // 获取表即列提示 hintTables: Api.newGet('/dbs/{id}/hint-tables'), sqlExec: Api.newPost('/dbs/{id}/exec-sql'), @@ -28,6 +29,7 @@ export const dbApi = { instances: Api.newGet('/instances'), getInstance: Api.newGet('/instances/{instanceId}'), getAllDatabase: Api.newGet('/instances/{instanceId}/databases'), + testConn: Api.newPost('/instances/test-conn'), saveInstance: Api.newPost('/instances'), getInstancePwd: Api.newGet('/instances/{id}/pwd'), deleteInstance: Api.newDelete('/instances/{id}'), diff --git a/mayfly_go_web/src/views/ops/db/component/tab/Query.vue b/mayfly_go_web/src/views/ops/db/component/sqleditor/DbSqlEditor.vue similarity index 92% rename from mayfly_go_web/src/views/ops/db/component/tab/Query.vue rename to mayfly_go_web/src/views/ops/db/component/sqleditor/DbSqlEditor.vue index 8790d9a1..e07a35bb 100644 --- a/mayfly_go_web/src/views/ops/db/component/tab/Query.vue +++ b/mayfly_go_web/src/views/ops/db/component/sqleditor/DbSqlEditor.vue @@ -44,7 +44,7 @@ - +
@@ -69,10 +69,10 @@ 取消 - + >
@@ -97,8 +97,8 @@ import { ElMessage, ElMessageBox } from 'element-plus'; import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; import { editor } from 'monaco-editor'; -import DbTable from '../DbTable.vue'; -import { TabInfo } from '../../db'; +import DbTableData from '@/views/ops/db/component/table/DbTableData.vue'; +import { DbInst } from '../../db'; import { exportCsv } from '@/common/utils/export'; import { dateStrFormat } from '@/common/utils/date'; import { dbApi } from '../../api'; @@ -113,15 +113,18 @@ import syssocket from '@/common/syssocket'; const emits = defineEmits(['saveSqlSuccess', 'deleteSqlSuccess']); const props = defineProps({ - data: { - type: TabInfo, + dbId: { + type: Number, + required: true, + }, + dbName: { + type: String, required: true, }, // sql脚本名,若有则去加载该sql内容 - // sqlName: { - // type: String, - // default: '', - // }, + sqlName: { + type: String, + }, editorHeight: { type: String, default: '600', @@ -136,9 +139,6 @@ let monacoEditor: editor.IStandaloneCodeEditor; const state = reactive({ token, - ti: {} as TabInfo, - dbs: [], - dbId: null, // 当前选中操作的数据库实例 table: '', // 当前单表操作sql的表信息 sqlName: '', sql: '', // 当前编辑器的sql内容 @@ -153,7 +153,7 @@ const state = reactive({ hasUpdatedFileds: false, }); -const { tableDataHeight, ti, execRes, table, sqlName, loading, hasUpdatedFileds } = toRefs(state); +const { tableDataHeight, execRes, table, loading, hasUpdatedFileds } = toRefs(state); watch( () => props.editorHeight, @@ -162,22 +162,22 @@ watch( } ); +const getNowDbInst = () => { + return DbInst.getInst(props.dbId); +}; + onMounted(async () => { console.log('in query mounted'); - state.ti = props.data; state.editorHeight = props.editorHeight; - const params = state.ti.params; - state.dbs = params && params.dbs; - if (params && params.sqlName) { - state.sqlName = params.sqlName; - const res = await dbApi.getSql.request({ id: state.ti.dbId, type: 1, name: state.sqlName, db: state.ti.db }); + if (props.sqlName) { + const res = await dbApi.getSql.request({ id: props.dbId, type: 1, name: state.sqlName, db: props.dbName }); state.sql = res.sql; } nextTick(() => { setTimeout(() => initMonacoEditor(), 50); }); - await state.ti.getNowDbInst().loadDbHints(state.ti.db); + await getNowDbInst().loadDbHints(props.dbName); }); const initMonacoEditor = () => { @@ -186,7 +186,8 @@ const initMonacoEditor = () => { // 注册快捷键:ctrl + R 运行选中的sql monacoEditor.addAction({ // An unique identifier of the contributed action. - id: 'run-sql-action' + state.ti.key, + // id: 'run-sql-action' + state.ti.key, + id: 'run-sql-action' + getKey(), // A label of the action that will be presented to the user. label: '执行SQL', // A precondition for this action. @@ -213,7 +214,7 @@ const initMonacoEditor = () => { // 注册快捷键:ctrl + shift + f 格式化sql monacoEditor.addAction({ // An unique identifier of the contributed action. - id: 'format-sql-action' + state.ti.key, + id: 'format-sql-action' + getKey(), // A label of the action that will be presented to the user. label: '格式化SQL', // A precondition for this action. @@ -245,7 +246,7 @@ const onDragSetHeight = () => { document.onmousemove = (e) => { e.preventDefault(); //得到鼠标拖动的宽高距离:取绝对值 - state.editorHeight = `${document.getElementById('MonacoTextarea-' + state.ti.key)!.clientHeight + e.movementY}px`; + state.editorHeight = `${document.getElementById('MonacoTextarea-' + getKey())!.clientHeight + e.movementY}px`; state.tableDataHeight -= e.movementY; }; document.onmouseup = () => { @@ -253,6 +254,10 @@ const onDragSetHeight = () => { }; }; +const getKey = () => { + return props.dbId + ':' + props.dbName; +}; + /** * 执行sql */ @@ -290,7 +295,7 @@ const onRunSql = async () => { try { state.loading = true; - const colAndData: any = await state.ti.getNowDbInst().runSql(state.ti.db, sql, execRemark); + const colAndData: any = await getNowDbInst().runSql(props.dbName, sql, execRemark); if (!colAndData.res || colAndData.res.length === 0) { ElMessage.warning('未查询到结果集'); } @@ -370,16 +375,17 @@ const saveSql = async () => { } } - await dbApi.saveSql.request({ id: state.ti.dbId, db: state.ti.db, sql: sql, type: 1, name: sqlName }); + await dbApi.saveSql.request({ id: props.dbId, db: props.dbName, sql: sql, type: 1, name: sqlName }); ElMessage.success('保存成功'); // 保存sql脚本成功事件 - emits('saveSqlSuccess', state.ti.dbId, state.ti.db); + emits('saveSqlSuccess', props.dbId, props.dbName); }; const deleteSql = async () => { const sqlName = state.sqlName; notBlank(sqlName, '该sql内容未保存'); - const { dbId, db } = state.ti; + const dbId = props.dbId; + const db = props.dbName; try { await ElMessageBox.confirm(`确定删除【${sqlName}】该SQL内容?`, '提示', { confirmButtonText: '确定', @@ -415,7 +421,7 @@ const formatSql = () => { * 提交事务,用于没有开启自动提交事务 */ const onCommit = () => { - state.ti.getNowDbInst().runSql(state.ti.db, 'COMMIT;'); + getNowDbInst().runSql(props.dbName, 'COMMIT;'); ElMessage.success('COMMIT success'); }; @@ -528,7 +534,7 @@ const execSqlFileSuccess = (res: any) => { // 获取sql文件上传执行url const getUploadSqlFileUrl = () => { - return `${config.baseApiUrl}/dbs/${state.ti.dbId}/exec-sql-file?db=${state.ti.db}&${joinClientParams()}`; + return `${config.baseApiUrl}/dbs/${props.dbId}/exec-sql-file?db=${props.dbName}&${joinClientParams()}`; }; const onDataSelectionChange = (datas: []) => { @@ -546,8 +552,8 @@ const changeUpdatedField = (updatedFields: []) => { const onDeleteData = async () => { const deleteDatas = state.selectionDatas; isTrue(deleteDatas && deleteDatas.length > 0, '请先选择要删除的数据'); - const { db } = state.ti; - const dbInst = state.ti.getNowDbInst(); + const db = props.dbName; + const dbInst = getNowDbInst(); const primaryKey = await dbInst.loadTableColumn(db, state.table); const primaryKeyColumnName = primaryKey.columnName; dbInst.promptExeSql(db, dbInst.genDeleteByPrimaryKeysSql(db, state.table, deleteDatas), null, () => { diff --git a/mayfly_go_web/src/views/ops/db/component/SqlExecBox.ts b/mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecBox.ts similarity index 100% rename from mayfly_go_web/src/views/ops/db/component/SqlExecBox.ts rename to mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecBox.ts diff --git a/mayfly_go_web/src/views/ops/db/component/SqlExecDialog.vue b/mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecDialog.vue similarity index 98% rename from mayfly_go_web/src/views/ops/db/component/SqlExecDialog.vue rename to mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecDialog.vue index 61ad68fe..7edc3046 100644 --- a/mayfly_go_web/src/views/ops/db/component/SqlExecDialog.vue +++ b/mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecDialog.vue @@ -15,7 +15,7 @@