mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 00:10:25 +08:00 
			
		
		
		
	fix: 数据库多库切换关键字提示错误修复&sql编辑器组件统一
This commit is contained in:
		@@ -9,7 +9,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { ref, watch, toRefs, reactive, onMounted, onBeforeUnmount } from 'vue';
 | 
					import { ref, watch, toRefs, reactive, onMounted, onBeforeUnmount } from 'vue';
 | 
				
			||||||
// import * as monaco from 'monaco-editor';
 | 
					 | 
				
			||||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
 | 
					import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
 | 
				
			||||||
// 相关语言
 | 
					// 相关语言
 | 
				
			||||||
import 'monaco-editor/esm/vs/basic-languages/shell/shell.contribution.js';
 | 
					import 'monaco-editor/esm/vs/basic-languages/shell/shell.contribution.js';
 | 
				
			||||||
@@ -155,7 +154,22 @@ const options = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const monacoTextarea: any = ref();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let monacoEditorIns: editor.IStandaloneCodeEditor = null as any;
 | 
				
			||||||
 | 
					let completionItemProvider: any = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					self.MonacoEnvironment = {
 | 
				
			||||||
 | 
					    getWorker(_: any, label: string) {
 | 
				
			||||||
 | 
					        if (label === 'json') {
 | 
				
			||||||
 | 
					            return new JsonWorker();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return new EditorWorker();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state = reactive({
 | 
					const state = reactive({
 | 
				
			||||||
 | 
					    editorHeight: '500px',
 | 
				
			||||||
    languageMode: 'shell',
 | 
					    languageMode: 'shell',
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -173,6 +187,7 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
        monacoEditorIns.dispose();
 | 
					        monacoEditorIns.dispose();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (completionItemProvider) {
 | 
					    if (completionItemProvider) {
 | 
				
			||||||
 | 
					        console.log('unmount=> dispose completion item provider');
 | 
				
			||||||
        completionItemProvider.dispose();
 | 
					        completionItemProvider.dispose();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@@ -203,20 +218,6 @@ watch(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const monacoTextarea: any = ref(null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let monacoEditorIns: editor.IStandaloneCodeEditor = null as any;
 | 
					 | 
				
			||||||
let completionItemProvider: any = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
self.MonacoEnvironment = {
 | 
					 | 
				
			||||||
    getWorker(_: any, label: string) {
 | 
					 | 
				
			||||||
        if (label === 'json') {
 | 
					 | 
				
			||||||
            return new JsonWorker();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return new EditorWorker();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const initMonacoEditorIns = () => {
 | 
					const initMonacoEditorIns = () => {
 | 
				
			||||||
    console.log('初始化monaco编辑器');
 | 
					    console.log('初始化monaco编辑器');
 | 
				
			||||||
    // options参数参考 https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html#language
 | 
					    // options参数参考 https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html#language
 | 
				
			||||||
@@ -260,6 +261,7 @@ const setEditorValue = (value: any) => {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
const registerCompletionItemProvider = () => {
 | 
					const registerCompletionItemProvider = () => {
 | 
				
			||||||
    if (completionItemProvider) {
 | 
					    if (completionItemProvider) {
 | 
				
			||||||
 | 
					        console.log('exist competion item provider, dispose now');
 | 
				
			||||||
        completionItemProvider.dispose();
 | 
					        completionItemProvider.dispose();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (state.languageMode == 'shell') {
 | 
					    if (state.languageMode == 'shell') {
 | 
				
			||||||
@@ -299,7 +301,11 @@ const format = () => {
 | 
				
			|||||||
    monacoEditorIns.trigger('', 'editor.action.formatDocument', '');
 | 
					    monacoEditorIns.trigger('', 'editor.action.formatDocument', '');
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineExpose({ format });
 | 
					const getEditor = () => {
 | 
				
			||||||
 | 
					    return monacoEditorIns;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineExpose({ getEditor, format });
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * key: language, value: CompletionItemProvider
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const completionItemProviders: Map<string, any> = new Map();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function registerCompletionItemProvider(language: string, completionItemProvider: any, replace: boolean = true) {
 | 
				
			||||||
 | 
					    const exist = completionItemProviders.get(language);
 | 
				
			||||||
 | 
					    if (exist) {
 | 
				
			||||||
 | 
					        if (!replace) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        exist.dispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    completionItemProviders.set(language, monaco.languages.registerCompletionItemProvider(language, completionItemProvider));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function dispposeCompletionItemProvider(language: string) {
 | 
				
			||||||
 | 
					    const exist = completionItemProviders.get(language);
 | 
				
			||||||
 | 
					    if (exist) {
 | 
				
			||||||
 | 
					        exist.dispose();
 | 
				
			||||||
 | 
					        completionItemProviders.delete(language);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								mayfly_go_web/src/types/shim.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								mayfly_go_web/src/types/shim.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -1,14 +1,5 @@
 | 
				
			|||||||
/* eslint-disable */
 | 
					 | 
				
			||||||
import {IDisposable} from 'monaco-editor';
 | 
					 | 
				
			||||||
declare global {
 | 
					 | 
				
			||||||
	interface Window {
 | 
					 | 
				
			||||||
		completionItemProvider?: IDisposable | undefined;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 申明外部 npm 插件模块
 | 
					// 申明外部 npm 插件模块
 | 
				
			||||||
declare module 'sql-formatter';
 | 
					declare module 'sql-formatter';
 | 
				
			||||||
declare module 'jsoneditor';
 | 
					declare module 'jsoneditor';
 | 
				
			||||||
declare module 'asciinema-player';
 | 
					declare module 'asciinema-player';
 | 
				
			||||||
declare module 'monaco-editor';
 | 
					 | 
				
			||||||
declare module 'vue-grid-layout';
 | 
					declare module 'vue-grid-layout';
 | 
				
			||||||
@@ -95,13 +95,14 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { defineAsyncComponent, onMounted, reactive, ref, toRefs } from 'vue';
 | 
					import { defineAsyncComponent, onMounted, reactive, ref, toRefs, onBeforeUnmount } from 'vue';
 | 
				
			||||||
import { ElMessage } from 'element-plus';
 | 
					import { ElMessage } from 'element-plus';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DbInst, TabInfo, TabType } from './db';
 | 
					import { DbInst, TabInfo, TabType, registerDbCompletionItemProvider } from './db';
 | 
				
			||||||
import { TagTreeNode } from '../component/tag';
 | 
					import { TagTreeNode } from '../component/tag';
 | 
				
			||||||
import TagTree from '../component/TagTree.vue';
 | 
					import TagTree from '../component/TagTree.vue';
 | 
				
			||||||
import { dbApi } from './api';
 | 
					import { dbApi } from './api';
 | 
				
			||||||
 | 
					import { dispposeCompletionItemProvider } from '../../../components/monaco/completionItemProvider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Query = defineAsyncComponent(() => import('./component/tab/Query.vue'));
 | 
					const Query = defineAsyncComponent(() => import('./component/tab/Query.vue'));
 | 
				
			||||||
const TableData = defineAsyncComponent(() => import('./component/tab/TableData.vue'));
 | 
					const TableData = defineAsyncComponent(() => import('./component/tab/TableData.vue'));
 | 
				
			||||||
@@ -144,12 +145,15 @@ const state = reactive({
 | 
				
			|||||||
const { nowDbInst } = toRefs(state);
 | 
					const { nowDbInst } = toRefs(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(() => {
 | 
					onMounted(() => {
 | 
				
			||||||
    self.completionItemProvider?.dispose();
 | 
					 | 
				
			||||||
    setHeight();
 | 
					    setHeight();
 | 
				
			||||||
    // 监听浏览器窗口大小变化,更新对应组件高度
 | 
					    // 监听浏览器窗口大小变化,更新对应组件高度
 | 
				
			||||||
    window.onresize = () => setHeight();
 | 
					    window.onresize = () => setHeight();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onBeforeUnmount(() => {
 | 
				
			||||||
 | 
					    dispposeCompletionItemProvider('sql');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 设置editor高度和数据表高度
 | 
					 * 设置editor高度和数据表高度
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -207,7 +211,6 @@ const loadNode = async (node: any) => {
 | 
				
			|||||||
    // 点击数据库实例 -> 加载库列表
 | 
					    // 点击数据库实例 -> 加载库列表
 | 
				
			||||||
    if (nodeType === NodeType.DbInst) {
 | 
					    if (nodeType === NodeType.DbInst) {
 | 
				
			||||||
        const dbs = params.database.split(' ')?.sort();
 | 
					        const dbs = params.database.split(' ')?.sort();
 | 
				
			||||||
        console.log(dbs);
 | 
					 | 
				
			||||||
        return dbs.map((x: any) => {
 | 
					        return dbs.map((x: any) => {
 | 
				
			||||||
            return new TagTreeNode(`${data.key}.${x}`, x, NodeType.Db).withParams({
 | 
					            return new TagTreeNode(`${data.key}.${x}`, x, NodeType.Db).withParams({
 | 
				
			||||||
                tagPath: params.tagPath,
 | 
					                tagPath: params.tagPath,
 | 
				
			||||||
@@ -406,9 +409,15 @@ const onTabChange = () => {
 | 
				
			|||||||
        state.db = '';
 | 
					        state.db = '';
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const nowTab = state.tabs.get(state.activeName);
 | 
					    const nowTab = state.tabs.get(state.activeName);
 | 
				
			||||||
    state.nowDbInst = DbInst.getInst(nowTab?.dbId);
 | 
					    state.nowDbInst = DbInst.getInst(nowTab?.dbId);
 | 
				
			||||||
    state.db = nowTab?.db as string;
 | 
					    state.db = nowTab?.db as string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nowTab?.type == TabType.Query) {
 | 
				
			||||||
 | 
					        // 注册sql提示
 | 
				
			||||||
 | 
					        registerDbCompletionItemProvider('sql', nowTab.dbId, nowTab.db, nowTab.params.dbs);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const onGenerateInsertSql = async (sql: string) => {
 | 
					const onGenerateInsertSql = async (sql: string) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,9 +44,7 @@
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="mt5 sqlEditor">
 | 
					        <MonacoEditor ref="monacoEditorRef" class="mt5" v-model="state.sql" language="sql" :height="editorHeight" :id="'MonacoTextarea-' + ti.key" />
 | 
				
			||||||
            <div :id="'MonacoTextarea-' + ti.key" :style="{ height: editorHeight }"></div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="editor-move-resize" @mousedown="onDragSetHeight">
 | 
					        <div class="editor-move-resize" @mousedown="onDragSetHeight">
 | 
				
			||||||
            <el-icon>
 | 
					            <el-icon>
 | 
				
			||||||
@@ -90,44 +88,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { nextTick, watch, onMounted, reactive, toRefs, ref, Ref } from 'vue';
 | 
					import { nextTick, watch, onMounted, reactive, toRefs, ref, Ref } from 'vue';
 | 
				
			||||||
import { storeToRefs } from 'pinia';
 | 
					 | 
				
			||||||
import { useThemeConfig } from '@/store/themeConfig';
 | 
					 | 
				
			||||||
import { getToken } from '@/common/utils/storage';
 | 
					import { getToken } from '@/common/utils/storage';
 | 
				
			||||||
import { isTrue, notBlank } from '@/common/assert';
 | 
					import { isTrue, notBlank } from '@/common/assert';
 | 
				
			||||||
import { format as sqlFormatter } from 'sql-formatter';
 | 
					import { format as sqlFormatter } from 'sql-formatter';
 | 
				
			||||||
import config from '@/common/config';
 | 
					import config from '@/common/config';
 | 
				
			||||||
import { ElMessage, ElMessageBox } from 'element-plus';
 | 
					import { ElMessage, ElMessageBox } from 'element-plus';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/mysql/mysql.js';
 | 
					 | 
				
			||||||
import { language as addSqlLanguage } from '../../lang/mysql.js';
 | 
					 | 
				
			||||||
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker';
 | 
					 | 
				
			||||||
// import * as monaco from 'monaco-editor';
 | 
					 | 
				
			||||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
 | 
					import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
 | 
				
			||||||
import { editor, languages, Position } from 'monaco-editor';
 | 
					import { editor } from 'monaco-editor';
 | 
				
			||||||
// 相关语言
 | 
					 | 
				
			||||||
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution.js';
 | 
					 | 
				
			||||||
import 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestController.js';
 | 
					 | 
				
			||||||
import 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestInlineCompletions.js';
 | 
					 | 
				
			||||||
// 右键菜单
 | 
					 | 
				
			||||||
import 'monaco-editor/esm/vs/editor/contrib/contextmenu/browser/contextmenu.js';
 | 
					 | 
				
			||||||
import 'monaco-editor/esm/vs/editor/contrib/caretOperations/browser/caretOperations.js';
 | 
					 | 
				
			||||||
import 'monaco-editor/esm/vs/editor/contrib/clipboard//browser/clipboard.js';
 | 
					 | 
				
			||||||
import 'monaco-editor/esm/vs/editor/contrib/find/browser/findController.js';
 | 
					 | 
				
			||||||
import 'monaco-editor/esm/vs/editor/contrib/format//browser/formatActions.js';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 主题仓库 https://github.com/brijeshb42/monaco-themes
 | 
					 | 
				
			||||||
// 主题例子 https://editor.bitwiser.in/
 | 
					 | 
				
			||||||
import SolarizedLight from 'monaco-themes/themes/Solarized-light.json';
 | 
					 | 
				
			||||||
import DbTable from '../DbTable.vue';
 | 
					import DbTable from '../DbTable.vue';
 | 
				
			||||||
import { DbInst, TabInfo } from '../../db';
 | 
					import { TabInfo } from '../../db';
 | 
				
			||||||
import { exportCsv } from '@/common/utils/export';
 | 
					import { exportCsv } from '@/common/utils/export';
 | 
				
			||||||
import { dateStrFormat } from '@/common/utils/date';
 | 
					import { dateStrFormat } from '@/common/utils/date';
 | 
				
			||||||
import { dbApi } from '../../api';
 | 
					import { dbApi } from '../../api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const sqlCompletionKeywords = [...sqlLanguage.keywords, ...addSqlLanguage.keywords];
 | 
					import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
 | 
				
			||||||
const sqlCompletionOperators = [...sqlLanguage.operators, ...addSqlLanguage.operators];
 | 
					 | 
				
			||||||
const sqlCompletionBuiltinFunctions = [...sqlLanguage.builtinFunctions, ...addSqlLanguage.builtinFunctions];
 | 
					 | 
				
			||||||
const sqlCompletionBuiltinVariables = [...sqlLanguage.builtinVariables, ...addSqlLanguage.builtinVariables];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const emits = defineEmits(['saveSqlSuccess', 'deleteSqlSuccess']);
 | 
					const emits = defineEmits(['saveSqlSuccess', 'deleteSqlSuccess']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -147,11 +123,12 @@ const props = defineProps({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { themeConfig } = storeToRefs(useThemeConfig());
 | 
					 | 
				
			||||||
const token = getToken();
 | 
					const token = getToken();
 | 
				
			||||||
let monacoEditor = {} as editor.IStandaloneCodeEditor;
 | 
					const monacoEditorRef: any = ref(null);
 | 
				
			||||||
const dbTableRef = ref(null) as Ref;
 | 
					const dbTableRef = ref(null) as Ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let monacoEditor: editor.IStandaloneCodeEditor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state = reactive({
 | 
					const state = reactive({
 | 
				
			||||||
    token,
 | 
					    token,
 | 
				
			||||||
    ti: {} as TabInfo,
 | 
					    ti: {} as TabInfo,
 | 
				
			||||||
@@ -180,15 +157,6 @@ watch(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 监听 themeConfig editorTheme配置文件的变化
 | 
					 | 
				
			||||||
watch(
 | 
					 | 
				
			||||||
    () => themeConfig.value.editorTheme,
 | 
					 | 
				
			||||||
    (val) => {
 | 
					 | 
				
			||||||
        console.log('monaco editor theme change: ', val);
 | 
					 | 
				
			||||||
        monaco?.editor?.setTheme(val);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
onMounted(async () => {
 | 
					onMounted(async () => {
 | 
				
			||||||
    console.log('in query mounted');
 | 
					    console.log('in query mounted');
 | 
				
			||||||
    state.ti = props.data;
 | 
					    state.ti = props.data;
 | 
				
			||||||
@@ -207,39 +175,8 @@ onMounted(async () => {
 | 
				
			|||||||
    await state.ti.getNowDbInst().loadDbHints(state.ti.db);
 | 
					    await state.ti.getNowDbInst().loadDbHints(state.ti.db);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
self.MonacoEnvironment = {
 | 
					 | 
				
			||||||
    getWorker() {
 | 
					 | 
				
			||||||
        return new EditorWorker();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const initMonacoEditor = () => {
 | 
					const initMonacoEditor = () => {
 | 
				
			||||||
    registerSqlCompletionItemProvider();
 | 
					    monacoEditor = monacoEditorRef.value.getEditor();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    let monacoTextarea = document.getElementById('MonacoTextarea-' + state.ti.key) as HTMLElement;
 | 
					 | 
				
			||||||
    // options参数参考 https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html#language
 | 
					 | 
				
			||||||
    // 初始化一些主题
 | 
					 | 
				
			||||||
    monaco.editor.defineTheme('SolarizedLight', SolarizedLight);
 | 
					 | 
				
			||||||
    monacoEditor = monaco.editor.create(monacoTextarea, {
 | 
					 | 
				
			||||||
        language: 'sql',
 | 
					 | 
				
			||||||
        theme: themeConfig.value.editorTheme,
 | 
					 | 
				
			||||||
        automaticLayout: true, //自适应宽高布局
 | 
					 | 
				
			||||||
        folding: false,
 | 
					 | 
				
			||||||
        roundedSelection: false, // 禁用选择文本背景的圆角
 | 
					 | 
				
			||||||
        matchBrackets: 'near',
 | 
					 | 
				
			||||||
        linkedEditing: true,
 | 
					 | 
				
			||||||
        cursorBlinking: 'smooth', // 光标闪烁样式
 | 
					 | 
				
			||||||
        mouseWheelZoom: true, // 在按住Ctrl键的同时使用鼠标滚轮时,在编辑器中缩放字体
 | 
					 | 
				
			||||||
        overviewRulerBorder: false, // 不要滚动条的边框
 | 
					 | 
				
			||||||
        tabSize: 2, // tab 缩进长度
 | 
					 | 
				
			||||||
        // fontFamily: 'JetBrainsMono', // 字体 暂时不要设置,否则光标容易错位
 | 
					 | 
				
			||||||
        fontWeight: 'bold',
 | 
					 | 
				
			||||||
        // letterSpacing: 1, 字符间距
 | 
					 | 
				
			||||||
        // quickSuggestions:false, // 禁用代码提示
 | 
					 | 
				
			||||||
        minimap: {
 | 
					 | 
				
			||||||
            enabled: false, // 不要小地图
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 注册快捷键:ctrl + R 运行选中的sql
 | 
					    // 注册快捷键:ctrl + R 运行选中的sql
 | 
				
			||||||
    monacoEditor.addAction({
 | 
					    monacoEditor.addAction({
 | 
				
			||||||
@@ -294,11 +231,6 @@ const initMonacoEditor = () => {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // 如果sql有值,则默认赋值
 | 
					 | 
				
			||||||
    if (state.sql) {
 | 
					 | 
				
			||||||
        monacoEditor.getModel()?.setValue(state.sql);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -308,7 +240,7 @@ const onDragSetHeight = () => {
 | 
				
			|||||||
    document.onmousemove = (e) => {
 | 
					    document.onmousemove = (e) => {
 | 
				
			||||||
        e.preventDefault();
 | 
					        e.preventDefault();
 | 
				
			||||||
        //得到鼠标拖动的宽高距离:取绝对值
 | 
					        //得到鼠标拖动的宽高距离:取绝对值
 | 
				
			||||||
        state.editorHeight = `${document.getElementById('MonacoTextarea-' + state.ti.key)!.offsetHeight + e.movementY}px`;
 | 
					        state.editorHeight = `${document.getElementById('MonacoTextarea-' + state.ti.key)!.clientHeight + e.movementY}px`;
 | 
				
			||||||
        state.tableDataHeight -= e.movementY;
 | 
					        state.tableDataHeight -= e.movementY;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    document.onmouseup = () => {
 | 
					    document.onmouseup = () => {
 | 
				
			||||||
@@ -590,308 +522,6 @@ const submitUpdateFields = () => {
 | 
				
			|||||||
const cancelUpdateFields = () => {
 | 
					const cancelUpdateFields = () => {
 | 
				
			||||||
    dbTableRef.value.cancelUpdateFields();
 | 
					    dbTableRef.value.cancelUpdateFields();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
const registerSqlCompletionItemProvider = () => {
 | 
					 | 
				
			||||||
    // 参考 https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-completion-provider-example
 | 
					 | 
				
			||||||
    self.completionItemProvider =
 | 
					 | 
				
			||||||
        self.completionItemProvider ||
 | 
					 | 
				
			||||||
        monaco.languages.registerCompletionItemProvider('sql', {
 | 
					 | 
				
			||||||
            triggerCharacters: ['.', ' '],
 | 
					 | 
				
			||||||
            provideCompletionItems: async (model: editor.ITextModel, position: Position): Promise<languages.CompletionList | null | undefined> => {
 | 
					 | 
				
			||||||
                let word = model.getWordUntilPosition(position);
 | 
					 | 
				
			||||||
                const nowTab = props.data;
 | 
					 | 
				
			||||||
                if (!nowTab) {
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                const { db, dbId } = nowTab;
 | 
					 | 
				
			||||||
                const dbInst = DbInst.getInst(dbId);
 | 
					 | 
				
			||||||
                const { lineNumber, column } = position;
 | 
					 | 
				
			||||||
                const { startColumn, endColumn } = word;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // 当前行文本
 | 
					 | 
				
			||||||
                let lineContent = model.getLineContent(lineNumber);
 | 
					 | 
				
			||||||
                // 注释行不需要代码提示
 | 
					 | 
				
			||||||
                if (lineContent.startsWith('--')) {
 | 
					 | 
				
			||||||
                    return { suggestions: [] };
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let range = {
 | 
					 | 
				
			||||||
                    startLineNumber: lineNumber,
 | 
					 | 
				
			||||||
                    endLineNumber: lineNumber,
 | 
					 | 
				
			||||||
                    startColumn,
 | 
					 | 
				
			||||||
                    endColumn,
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                //  光标前文本
 | 
					 | 
				
			||||||
                const textBeforePointer = model.getValueInRange({
 | 
					 | 
				
			||||||
                    startLineNumber: lineNumber,
 | 
					 | 
				
			||||||
                    startColumn: 0,
 | 
					 | 
				
			||||||
                    endLineNumber: lineNumber,
 | 
					 | 
				
			||||||
                    endColumn: column,
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                const textBeforePointerMulti = model.getValueInRange({
 | 
					 | 
				
			||||||
                    startLineNumber: 1,
 | 
					 | 
				
			||||||
                    startColumn: 0,
 | 
					 | 
				
			||||||
                    endLineNumber: lineNumber,
 | 
					 | 
				
			||||||
                    endColumn: column,
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                // 光标后文本
 | 
					 | 
				
			||||||
                const textAfterPointerMulti = model.getValueInRange({
 | 
					 | 
				
			||||||
                    startLineNumber: lineNumber,
 | 
					 | 
				
			||||||
                    startColumn: column,
 | 
					 | 
				
			||||||
                    endLineNumber: model.getLineCount(),
 | 
					 | 
				
			||||||
                    endColumn: model.getLineMaxColumn(model.getLineCount()),
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                // // const nextTokens = textAfterPointer.trim().split(/\s+/)
 | 
					 | 
				
			||||||
                // // const nextToken = nextTokens[0].toLowerCase()
 | 
					 | 
				
			||||||
                const tokens = textBeforePointer.trim().split(/\s+/);
 | 
					 | 
				
			||||||
                let lastToken = tokens[tokens.length - 1].toLowerCase();
 | 
					 | 
				
			||||||
                const secondToken = (tokens.length > 2 && tokens[tokens.length - 2].toLowerCase()) || '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const dbs = (nowTab.params && nowTab.params.dbs && nowTab.params.dbs) || [];
 | 
					 | 
				
			||||||
                // console.log("光标前文本:=>" + textBeforePointerMulti)
 | 
					 | 
				
			||||||
                // console.log("最后输入的:=>" + lastToken)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let suggestions: languages.CompletionItem[] = [];
 | 
					 | 
				
			||||||
                const tables = await dbInst.loadTables(db);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                async function hintTableColumns(tableName: any, db: any) {
 | 
					 | 
				
			||||||
                    let dbHits = await dbInst.loadDbHints(db);
 | 
					 | 
				
			||||||
                    let columns = dbHits[tableName];
 | 
					 | 
				
			||||||
                    let suggestions: languages.CompletionItem[] = [];
 | 
					 | 
				
			||||||
                    columns?.forEach((a: string, index: any) => {
 | 
					 | 
				
			||||||
                        // 字段数据格式  字段名 字段注释,  如: create_time  [datetime][创建时间]
 | 
					 | 
				
			||||||
                        const nameAndComment = a.split('  ');
 | 
					 | 
				
			||||||
                        const fieldName = nameAndComment[0];
 | 
					 | 
				
			||||||
                        suggestions.push({
 | 
					 | 
				
			||||||
                            label: {
 | 
					 | 
				
			||||||
                                label: a,
 | 
					 | 
				
			||||||
                                description: 'column',
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            kind: monaco.languages.CompletionItemKind.Property,
 | 
					 | 
				
			||||||
                            detail: '', // 不显示detail, 否则选中时备注等会被遮挡
 | 
					 | 
				
			||||||
                            insertText: fieldName, // create_time
 | 
					 | 
				
			||||||
                            range,
 | 
					 | 
				
			||||||
                            sortText: 100 + index + '', // 使用表字段声明顺序排序,排序需为字符串类型
 | 
					 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                    return suggestions;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (lastToken.indexOf('.') > -1 || secondToken.indexOf('.') > -1) {
 | 
					 | 
				
			||||||
                    // 如果是.触发代码提示,则进行【 库.表名联想 】 或 【 表别名.表字段联想 】
 | 
					 | 
				
			||||||
                    let str = lastToken.substring(0, lastToken.lastIndexOf('.'));
 | 
					 | 
				
			||||||
                    if (lastToken.trim().startsWith('.')) {
 | 
					 | 
				
			||||||
                        str = secondToken;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    // 如果字符串粘连起了如:'a.creator,a.',需要重新取出别名
 | 
					 | 
				
			||||||
                    let aliasArr = lastToken.split(',');
 | 
					 | 
				
			||||||
                    if (aliasArr.length > 1) {
 | 
					 | 
				
			||||||
                        lastToken = aliasArr[aliasArr.length - 1];
 | 
					 | 
				
			||||||
                        str = lastToken.substring(0, lastToken.lastIndexOf('.'));
 | 
					 | 
				
			||||||
                        if (lastToken.trim().startsWith('.')) {
 | 
					 | 
				
			||||||
                            str = secondToken;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    // 库.表名联想
 | 
					 | 
				
			||||||
                    if (dbs && dbs.filter((a: any) => a === str)?.length > 0) {
 | 
					 | 
				
			||||||
                        let tables = await dbInst.loadTables(str);
 | 
					 | 
				
			||||||
                        let suggestions: languages.CompletionItem[] = [];
 | 
					 | 
				
			||||||
                        for (let item of tables) {
 | 
					 | 
				
			||||||
                            const { tableName, tableComment } = item;
 | 
					 | 
				
			||||||
                            suggestions.push({
 | 
					 | 
				
			||||||
                                label: {
 | 
					 | 
				
			||||||
                                    label: tableName + (tableComment ? ' - ' + tableComment : ''),
 | 
					 | 
				
			||||||
                                    description: 'table',
 | 
					 | 
				
			||||||
                                },
 | 
					 | 
				
			||||||
                                kind: monaco.languages.CompletionItemKind.File,
 | 
					 | 
				
			||||||
                                insertText: tableName,
 | 
					 | 
				
			||||||
                                range,
 | 
					 | 
				
			||||||
                            });
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        return { suggestions };
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    let sql = textBeforePointerMulti.split(';')[textBeforePointerMulti.split(';').length - 1] + textAfterPointerMulti.split(';')[0];
 | 
					 | 
				
			||||||
                    // 表别名.表字段联想
 | 
					 | 
				
			||||||
                    let tableInfo = getTableByAlias(sql, db, str);
 | 
					 | 
				
			||||||
                    if (tableInfo.tableName) {
 | 
					 | 
				
			||||||
                        let tableName = tableInfo.tableName;
 | 
					 | 
				
			||||||
                        let db = tableInfo.dbName;
 | 
					 | 
				
			||||||
                        // 取出表名并提示
 | 
					 | 
				
			||||||
                        let suggestions = await hintTableColumns(tableName, db);
 | 
					 | 
				
			||||||
                        if (suggestions.length > 0) {
 | 
					 | 
				
			||||||
                            return { suggestions };
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    return { suggestions: [] };
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    // 如果sql里含有表名,则提示表字段
 | 
					 | 
				
			||||||
                    let mat = textBeforePointerMulti.match(/[from|update]\n*\s+\n*(\w+)\n*\s+\n*/i);
 | 
					 | 
				
			||||||
                    if (mat && mat.length > 1) {
 | 
					 | 
				
			||||||
                        let tableName = mat[1];
 | 
					 | 
				
			||||||
                        // 取出表名并提示
 | 
					 | 
				
			||||||
                        let addSuggestions = await hintTableColumns(tableName, db);
 | 
					 | 
				
			||||||
                        if (addSuggestions.length > 0) {
 | 
					 | 
				
			||||||
                            suggestions = suggestions.concat(addSuggestions);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // 表名联想
 | 
					 | 
				
			||||||
                tables.forEach((tableMeta: any) => {
 | 
					 | 
				
			||||||
                    const { tableName, tableComment } = tableMeta;
 | 
					 | 
				
			||||||
                    suggestions.push({
 | 
					 | 
				
			||||||
                        label: {
 | 
					 | 
				
			||||||
                            label: tableName + ' - ' + tableComment,
 | 
					 | 
				
			||||||
                            description: 'table',
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        kind: monaco.languages.CompletionItemKind.File,
 | 
					 | 
				
			||||||
                        detail: tableComment,
 | 
					 | 
				
			||||||
                        insertText: tableName + ' ',
 | 
					 | 
				
			||||||
                        range,
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // mysql关键字
 | 
					 | 
				
			||||||
                sqlCompletionKeywords.forEach((item: any) => {
 | 
					 | 
				
			||||||
                    suggestions.push({
 | 
					 | 
				
			||||||
                        label: {
 | 
					 | 
				
			||||||
                            label: item,
 | 
					 | 
				
			||||||
                            description: 'keyword',
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        kind: monaco.languages.CompletionItemKind.Keyword,
 | 
					 | 
				
			||||||
                        insertText: item,
 | 
					 | 
				
			||||||
                        range,
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // 操作符
 | 
					 | 
				
			||||||
                sqlCompletionOperators.forEach((item: any) => {
 | 
					 | 
				
			||||||
                    suggestions.push({
 | 
					 | 
				
			||||||
                        label: {
 | 
					 | 
				
			||||||
                            label: item,
 | 
					 | 
				
			||||||
                            description: 'opt',
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        kind: monaco.languages.CompletionItemKind.Operator,
 | 
					 | 
				
			||||||
                        insertText: item,
 | 
					 | 
				
			||||||
                        range,
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let replacedFunctions = [] as string[];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // 添加的函数
 | 
					 | 
				
			||||||
                addSqlLanguage.replaceFunctions.forEach((item: any) => {
 | 
					 | 
				
			||||||
                    replacedFunctions.push(item.label);
 | 
					 | 
				
			||||||
                    suggestions.push({
 | 
					 | 
				
			||||||
                        label: {
 | 
					 | 
				
			||||||
                            label: item.label,
 | 
					 | 
				
			||||||
                            description: item.description,
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        kind: monaco.languages.CompletionItemKind.Function,
 | 
					 | 
				
			||||||
                        insertText: item.insertText,
 | 
					 | 
				
			||||||
                        range,
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // 内置函数
 | 
					 | 
				
			||||||
                sqlCompletionBuiltinFunctions.forEach((item: any) => {
 | 
					 | 
				
			||||||
                    replacedFunctions.indexOf(item) < 0 &&
 | 
					 | 
				
			||||||
                        suggestions.push({
 | 
					 | 
				
			||||||
                            label: {
 | 
					 | 
				
			||||||
                                label: item,
 | 
					 | 
				
			||||||
                                description: 'func',
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            kind: monaco.languages.CompletionItemKind.Function,
 | 
					 | 
				
			||||||
                            insertText: item,
 | 
					 | 
				
			||||||
                            range,
 | 
					 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                // 内置变量
 | 
					 | 
				
			||||||
                sqlCompletionBuiltinVariables.forEach((item: string) => {
 | 
					 | 
				
			||||||
                    suggestions.push({
 | 
					 | 
				
			||||||
                        label: {
 | 
					 | 
				
			||||||
                            label: item,
 | 
					 | 
				
			||||||
                            description: 'var',
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        kind: monaco.languages.CompletionItemKind.Variable,
 | 
					 | 
				
			||||||
                        insertText: item,
 | 
					 | 
				
			||||||
                        range,
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // 库名提示
 | 
					 | 
				
			||||||
                if (dbs && dbs.length > 0) {
 | 
					 | 
				
			||||||
                    dbs.forEach((a: any) => {
 | 
					 | 
				
			||||||
                        suggestions.push({
 | 
					 | 
				
			||||||
                            label: {
 | 
					 | 
				
			||||||
                                label: a,
 | 
					 | 
				
			||||||
                                description: 'schema',
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            kind: monaco.languages.CompletionItemKind.Folder,
 | 
					 | 
				
			||||||
                            insertText: a,
 | 
					 | 
				
			||||||
                            range,
 | 
					 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // 默认提示
 | 
					 | 
				
			||||||
                return {
 | 
					 | 
				
			||||||
                    suggestions: suggestions,
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * 根据别名获取sql里的表名
 | 
					 | 
				
			||||||
 * @param sql sql
 | 
					 | 
				
			||||||
 * @param db 默认数据库
 | 
					 | 
				
			||||||
 * @param alias 别名
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
const getTableByAlias = (sql: string, db: string, alias: string): { dbName: string; tableName: string } => {
 | 
					 | 
				
			||||||
    // 表别名:表名
 | 
					 | 
				
			||||||
    let result = {};
 | 
					 | 
				
			||||||
    let defName = '';
 | 
					 | 
				
			||||||
    let defResult = {};
 | 
					 | 
				
			||||||
    // 正则匹配取出表名和表别名
 | 
					 | 
				
			||||||
    // 测试sql
 | 
					 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    `select * from database.Outvisit l
 | 
					 | 
				
			||||||
left join patient p on l.patid=p.patientid
 | 
					 | 
				
			||||||
join patstatic c on   l.patid=c.patid inner join patphone  ph  on l.patid=ph.patid
 | 
					 | 
				
			||||||
where l.name='kevin' and exsits(select 1 from pharmacywestpas pw where p.outvisitid=l.outvisitid)
 | 
					 | 
				
			||||||
unit all
 | 
					 | 
				
			||||||
select * from invisit v where`.match(/(join|from)\s+(\w*-?\w*\.?\w+)\s*(as)?\s*(\w*)/gi)
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    let match = sql.match(/(join|from)\n*\s+\n*(\w*-?\w*\.?\w+)\s*(as)?\s*(\w*)\n*/gi);
 | 
					 | 
				
			||||||
    if (match && match.length > 0) {
 | 
					 | 
				
			||||||
        match.forEach((a) => {
 | 
					 | 
				
			||||||
            // 去掉前缀,取出
 | 
					 | 
				
			||||||
            let t = a
 | 
					 | 
				
			||||||
                .substring(5, a.length)
 | 
					 | 
				
			||||||
                .replaceAll(/\s+/g, ' ')
 | 
					 | 
				
			||||||
                .replaceAll(/\s+as\s+/gi, ' ')
 | 
					 | 
				
			||||||
                .replaceAll(/\r\n/g, ' ')
 | 
					 | 
				
			||||||
                .trim()
 | 
					 | 
				
			||||||
                .split(/\s+/);
 | 
					 | 
				
			||||||
            let withDb = t[0].split('.');
 | 
					 | 
				
			||||||
            // 表名是 db名.表名
 | 
					 | 
				
			||||||
            let tName = withDb.length > 1 ? withDb[1] : withDb[0];
 | 
					 | 
				
			||||||
            let dbName = withDb.length > 1 ? withDb[0] : db || '';
 | 
					 | 
				
			||||||
            if (t.length == 2) {
 | 
					 | 
				
			||||||
                // 表别名:表名
 | 
					 | 
				
			||||||
                result[t[1]] = { tableName: tName, dbName };
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                // 只有表名无别名 取第一个无别名的表为默认表
 | 
					 | 
				
			||||||
                !defName && (defResult = { tableName: tName, dbName: db });
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return result[alias] || defResult;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@@ -905,12 +535,6 @@ select * from invisit v where`.match(/(join|from)\s+(\w*-?\w*\.?\w+)\s*(as)?\s*(
 | 
				
			|||||||
    text-decoration: none;
 | 
					    text-decoration: none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.sqlEditor {
 | 
					 | 
				
			||||||
    font-size: 8pt;
 | 
					 | 
				
			||||||
    font-weight: 600;
 | 
					 | 
				
			||||||
    border: 1px solid var(--el-border-color-light, #ebeef5);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.update_field_active {
 | 
					.update_field_active {
 | 
				
			||||||
    background-color: var(--el-color-success);
 | 
					    background-color: var(--el-color-success);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,18 @@ import { dbApi } from './api';
 | 
				
			|||||||
import { getTextWidth } from '@/common/utils/string';
 | 
					import { getTextWidth } from '@/common/utils/string';
 | 
				
			||||||
import SqlExecBox from './component/SqlExecBox';
 | 
					import SqlExecBox from './component/SqlExecBox';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/mysql/mysql.js';
 | 
				
			||||||
 | 
					import { language as addSqlLanguage } from './lang/mysql.js';
 | 
				
			||||||
 | 
					import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
 | 
				
			||||||
 | 
					import { editor, languages, Position } from 'monaco-editor';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { registerCompletionItemProvider } from '@/components/monaco/completionItemProvider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const sqlCompletionKeywords = [...sqlLanguage.keywords, ...addSqlLanguage.keywords];
 | 
				
			||||||
 | 
					const sqlCompletionOperators = [...sqlLanguage.operators, ...addSqlLanguage.operators];
 | 
				
			||||||
 | 
					const sqlCompletionBuiltinFunctions = [...sqlLanguage.builtinFunctions, ...addSqlLanguage.builtinFunctions];
 | 
				
			||||||
 | 
					const sqlCompletionBuiltinVariables = [...sqlLanguage.builtinVariables, ...addSqlLanguage.builtinVariables];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const dbInstCache: Map<number, DbInst> = new Map();
 | 
					const dbInstCache: Map<number, DbInst> = new Map();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class DbInst {
 | 
					export class DbInst {
 | 
				
			||||||
@@ -463,3 +475,305 @@ export type FieldsMeta = {
 | 
				
			|||||||
    // 新值
 | 
					    // 新值
 | 
				
			||||||
    newValue: string;
 | 
					    newValue: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 注册数据库表、字段等信息提示
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param language 语言
 | 
				
			||||||
 | 
					 * @param dbId 数据库id
 | 
				
			||||||
 | 
					 * @param db 库名
 | 
				
			||||||
 | 
					 * @param dbs 该库所有库名
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function registerDbCompletionItemProvider(language: string, dbId: number, db: string, dbs: [] = []) {
 | 
				
			||||||
 | 
					    registerCompletionItemProvider(language, {
 | 
				
			||||||
 | 
					        triggerCharacters: ['.', ' '],
 | 
				
			||||||
 | 
					        provideCompletionItems: async (model: editor.ITextModel, position: Position): Promise<languages.CompletionList | null | undefined> => {
 | 
				
			||||||
 | 
					            let word = model.getWordUntilPosition(position);
 | 
				
			||||||
 | 
					            const dbInst = DbInst.getInst(dbId);
 | 
				
			||||||
 | 
					            const { lineNumber, column } = position;
 | 
				
			||||||
 | 
					            const { startColumn, endColumn } = word;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 当前行文本
 | 
				
			||||||
 | 
					            let lineContent = model.getLineContent(lineNumber);
 | 
				
			||||||
 | 
					            // 注释行不需要代码提示
 | 
				
			||||||
 | 
					            if (lineContent.startsWith('--')) {
 | 
				
			||||||
 | 
					                return { suggestions: [] };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let range = {
 | 
				
			||||||
 | 
					                startLineNumber: lineNumber,
 | 
				
			||||||
 | 
					                endLineNumber: lineNumber,
 | 
				
			||||||
 | 
					                startColumn,
 | 
				
			||||||
 | 
					                endColumn,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //  光标前文本
 | 
				
			||||||
 | 
					            const textBeforePointer = model.getValueInRange({
 | 
				
			||||||
 | 
					                startLineNumber: lineNumber,
 | 
				
			||||||
 | 
					                startColumn: 0,
 | 
				
			||||||
 | 
					                endLineNumber: lineNumber,
 | 
				
			||||||
 | 
					                endColumn: column,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            const textBeforePointerMulti = model.getValueInRange({
 | 
				
			||||||
 | 
					                startLineNumber: 1,
 | 
				
			||||||
 | 
					                startColumn: 0,
 | 
				
			||||||
 | 
					                endLineNumber: lineNumber,
 | 
				
			||||||
 | 
					                endColumn: column,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            // 光标后文本
 | 
				
			||||||
 | 
					            const textAfterPointerMulti = model.getValueInRange({
 | 
				
			||||||
 | 
					                startLineNumber: lineNumber,
 | 
				
			||||||
 | 
					                startColumn: column,
 | 
				
			||||||
 | 
					                endLineNumber: model.getLineCount(),
 | 
				
			||||||
 | 
					                endColumn: model.getLineMaxColumn(model.getLineCount()),
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            // // const nextTokens = textAfterPointer.trim().split(/\s+/)
 | 
				
			||||||
 | 
					            // // const nextToken = nextTokens[0].toLowerCase()
 | 
				
			||||||
 | 
					            const tokens = textBeforePointer.trim().split(/\s+/);
 | 
				
			||||||
 | 
					            let lastToken = tokens[tokens.length - 1].toLowerCase();
 | 
				
			||||||
 | 
					            const secondToken = (tokens.length > 2 && tokens[tokens.length - 2].toLowerCase()) || '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // console.log("光标前文本:=>" + textBeforePointerMulti)
 | 
				
			||||||
 | 
					            // console.log("最后输入的:=>" + lastToken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let suggestions: languages.CompletionItem[] = [];
 | 
				
			||||||
 | 
					            const tables = await dbInst.loadTables(db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            async function hintTableColumns(tableName: any, db: any) {
 | 
				
			||||||
 | 
					                let dbHits = await dbInst.loadDbHints(db);
 | 
				
			||||||
 | 
					                let columns = dbHits[tableName];
 | 
				
			||||||
 | 
					                let suggestions: languages.CompletionItem[] = [];
 | 
				
			||||||
 | 
					                columns?.forEach((a: string, index: any) => {
 | 
				
			||||||
 | 
					                    // 字段数据格式  字段名 字段注释,  如: create_time  [datetime][创建时间]
 | 
				
			||||||
 | 
					                    const nameAndComment = a.split('  ');
 | 
				
			||||||
 | 
					                    const fieldName = nameAndComment[0];
 | 
				
			||||||
 | 
					                    suggestions.push({
 | 
				
			||||||
 | 
					                        label: {
 | 
				
			||||||
 | 
					                            label: a,
 | 
				
			||||||
 | 
					                            description: 'column',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        kind: monaco.languages.CompletionItemKind.Property,
 | 
				
			||||||
 | 
					                        detail: '', // 不显示detail, 否则选中时备注等会被遮挡
 | 
				
			||||||
 | 
					                        insertText: fieldName, // create_time
 | 
				
			||||||
 | 
					                        range,
 | 
				
			||||||
 | 
					                        sortText: 100 + index + '', // 使用表字段声明顺序排序,排序需为字符串类型
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                return suggestions;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (lastToken.indexOf('.') > -1 || secondToken.indexOf('.') > -1) {
 | 
				
			||||||
 | 
					                // 如果是.触发代码提示,则进行【 库.表名联想 】 或 【 表别名.表字段联想 】
 | 
				
			||||||
 | 
					                let str = lastToken.substring(0, lastToken.lastIndexOf('.'));
 | 
				
			||||||
 | 
					                if (lastToken.trim().startsWith('.')) {
 | 
				
			||||||
 | 
					                    str = secondToken;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // 如果字符串粘连起了如:'a.creator,a.',需要重新取出别名
 | 
				
			||||||
 | 
					                let aliasArr = lastToken.split(',');
 | 
				
			||||||
 | 
					                if (aliasArr.length > 1) {
 | 
				
			||||||
 | 
					                    lastToken = aliasArr[aliasArr.length - 1];
 | 
				
			||||||
 | 
					                    str = lastToken.substring(0, lastToken.lastIndexOf('.'));
 | 
				
			||||||
 | 
					                    if (lastToken.trim().startsWith('.')) {
 | 
				
			||||||
 | 
					                        str = secondToken;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // 库.表名联想
 | 
				
			||||||
 | 
					                if (dbs && dbs.filter((a: any) => a === str)?.length > 0) {
 | 
				
			||||||
 | 
					                    let tables = await dbInst.loadTables(str);
 | 
				
			||||||
 | 
					                    let suggestions: languages.CompletionItem[] = [];
 | 
				
			||||||
 | 
					                    for (let item of tables) {
 | 
				
			||||||
 | 
					                        const { tableName, tableComment } = item;
 | 
				
			||||||
 | 
					                        suggestions.push({
 | 
				
			||||||
 | 
					                            label: {
 | 
				
			||||||
 | 
					                                label: tableName + (tableComment ? ' - ' + tableComment : ''),
 | 
				
			||||||
 | 
					                                description: 'table',
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            kind: monaco.languages.CompletionItemKind.File,
 | 
				
			||||||
 | 
					                            insertText: tableName,
 | 
				
			||||||
 | 
					                            range,
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    return { suggestions };
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let sql = textBeforePointerMulti.split(';')[textBeforePointerMulti.split(';').length - 1] + textAfterPointerMulti.split(';')[0];
 | 
				
			||||||
 | 
					                // 表别名.表字段联想
 | 
				
			||||||
 | 
					                let tableInfo = getTableByAlias(sql, db, str);
 | 
				
			||||||
 | 
					                if (tableInfo.tableName) {
 | 
				
			||||||
 | 
					                    let tableName = tableInfo.tableName;
 | 
				
			||||||
 | 
					                    let db = tableInfo.dbName;
 | 
				
			||||||
 | 
					                    // 取出表名并提示
 | 
				
			||||||
 | 
					                    let suggestions = await hintTableColumns(tableName, db);
 | 
				
			||||||
 | 
					                    if (suggestions.length > 0) {
 | 
				
			||||||
 | 
					                        return { suggestions };
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return { suggestions: [] };
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // 如果sql里含有表名,则提示表字段
 | 
				
			||||||
 | 
					                let mat = textBeforePointerMulti.match(/[from|update]\n*\s+\n*(\w+)\n*\s+\n*/i);
 | 
				
			||||||
 | 
					                if (mat && mat.length > 1) {
 | 
				
			||||||
 | 
					                    let tableName = mat[1];
 | 
				
			||||||
 | 
					                    // 取出表名并提示
 | 
				
			||||||
 | 
					                    let addSuggestions = await hintTableColumns(tableName, db);
 | 
				
			||||||
 | 
					                    if (addSuggestions.length > 0) {
 | 
				
			||||||
 | 
					                        suggestions = suggestions.concat(addSuggestions);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 表名联想
 | 
				
			||||||
 | 
					            tables.forEach((tableMeta: any, index: any) => {
 | 
				
			||||||
 | 
					                const { tableName, tableComment } = tableMeta;
 | 
				
			||||||
 | 
					                suggestions.push({
 | 
				
			||||||
 | 
					                    label: {
 | 
				
			||||||
 | 
					                        label: tableName + ' - ' + tableComment,
 | 
				
			||||||
 | 
					                        description: 'table',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    kind: monaco.languages.CompletionItemKind.File,
 | 
				
			||||||
 | 
					                    detail: tableComment,
 | 
				
			||||||
 | 
					                    insertText: tableName + ' ',
 | 
				
			||||||
 | 
					                    range,
 | 
				
			||||||
 | 
					                    sortText: 300 + index + '',
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // mysql关键字
 | 
				
			||||||
 | 
					            sqlCompletionKeywords.forEach((item: any) => {
 | 
				
			||||||
 | 
					                suggestions.push({
 | 
				
			||||||
 | 
					                    label: {
 | 
				
			||||||
 | 
					                        label: item,
 | 
				
			||||||
 | 
					                        description: 'keyword',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    kind: monaco.languages.CompletionItemKind.Keyword,
 | 
				
			||||||
 | 
					                    insertText: item,
 | 
				
			||||||
 | 
					                    range,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 操作符
 | 
				
			||||||
 | 
					            sqlCompletionOperators.forEach((item: any) => {
 | 
				
			||||||
 | 
					                suggestions.push({
 | 
				
			||||||
 | 
					                    label: {
 | 
				
			||||||
 | 
					                        label: item,
 | 
				
			||||||
 | 
					                        description: 'opt',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    kind: monaco.languages.CompletionItemKind.Operator,
 | 
				
			||||||
 | 
					                    insertText: item,
 | 
				
			||||||
 | 
					                    range,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let replacedFunctions = [] as string[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 添加的函数
 | 
				
			||||||
 | 
					            addSqlLanguage.replaceFunctions.forEach((item: any) => {
 | 
				
			||||||
 | 
					                replacedFunctions.push(item.label);
 | 
				
			||||||
 | 
					                suggestions.push({
 | 
				
			||||||
 | 
					                    label: {
 | 
				
			||||||
 | 
					                        label: item.label,
 | 
				
			||||||
 | 
					                        description: item.description,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    kind: monaco.languages.CompletionItemKind.Function,
 | 
				
			||||||
 | 
					                    insertText: item.insertText,
 | 
				
			||||||
 | 
					                    range,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 内置函数
 | 
				
			||||||
 | 
					            sqlCompletionBuiltinFunctions.forEach((item: any) => {
 | 
				
			||||||
 | 
					                replacedFunctions.indexOf(item) < 0 &&
 | 
				
			||||||
 | 
					                    suggestions.push({
 | 
				
			||||||
 | 
					                        label: {
 | 
				
			||||||
 | 
					                            label: item,
 | 
				
			||||||
 | 
					                            description: 'func',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        kind: monaco.languages.CompletionItemKind.Function,
 | 
				
			||||||
 | 
					                        insertText: item,
 | 
				
			||||||
 | 
					                        range,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            // 内置变量
 | 
				
			||||||
 | 
					            sqlCompletionBuiltinVariables.forEach((item: string) => {
 | 
				
			||||||
 | 
					                suggestions.push({
 | 
				
			||||||
 | 
					                    label: {
 | 
				
			||||||
 | 
					                        label: item,
 | 
				
			||||||
 | 
					                        description: 'var',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    kind: monaco.languages.CompletionItemKind.Variable,
 | 
				
			||||||
 | 
					                    insertText: item,
 | 
				
			||||||
 | 
					                    range,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 库名提示
 | 
				
			||||||
 | 
					            if (dbs && dbs.length > 0) {
 | 
				
			||||||
 | 
					                dbs.forEach((a: any) => {
 | 
				
			||||||
 | 
					                    suggestions.push({
 | 
				
			||||||
 | 
					                        label: {
 | 
				
			||||||
 | 
					                            label: a,
 | 
				
			||||||
 | 
					                            description: 'schema',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        kind: monaco.languages.CompletionItemKind.Folder,
 | 
				
			||||||
 | 
					                        insertText: a,
 | 
				
			||||||
 | 
					                        range,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 默认提示
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                suggestions: suggestions,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 根据别名获取sql里的表名
 | 
				
			||||||
 | 
					 * @param sql sql
 | 
				
			||||||
 | 
					 * @param db 默认数据库
 | 
				
			||||||
 | 
					 * @param alias 别名
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const getTableByAlias = (sql: string, db: string, alias: string): { dbName: string; tableName: string } => {
 | 
				
			||||||
 | 
					    // 表别名:表名
 | 
				
			||||||
 | 
					    let result = {};
 | 
				
			||||||
 | 
					    let defName = '';
 | 
				
			||||||
 | 
					    let defResult = {};
 | 
				
			||||||
 | 
					    // 正则匹配取出表名和表别名
 | 
				
			||||||
 | 
					    // 测试sql
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    `select * from database.Outvisit l
 | 
				
			||||||
 | 
					left join patient p on l.patid=p.patientid
 | 
				
			||||||
 | 
					join patstatic c on   l.patid=c.patid inner join patphone  ph  on l.patid=ph.patid
 | 
				
			||||||
 | 
					where l.name='kevin' and exsits(select 1 from pharmacywestpas pw where p.outvisitid=l.outvisitid)
 | 
				
			||||||
 | 
					unit all
 | 
				
			||||||
 | 
					select * from invisit v where`.match(/(join|from)\s+(\w*-?\w*\.?\w+)\s*(as)?\s*(\w*)/gi)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    let match = sql.match(/(join|from)\n*\s+\n*(\w*-?\w*\.?\w+)\s*(as)?\s*(\w*)\n*/gi);
 | 
				
			||||||
 | 
					    if (match && match.length > 0) {
 | 
				
			||||||
 | 
					        match.forEach((a) => {
 | 
				
			||||||
 | 
					            // 去掉前缀,取出
 | 
				
			||||||
 | 
					            let t = a
 | 
				
			||||||
 | 
					                .substring(5, a.length)
 | 
				
			||||||
 | 
					                .replaceAll(/\s+/g, ' ')
 | 
				
			||||||
 | 
					                .replaceAll(/\s+as\s+/gi, ' ')
 | 
				
			||||||
 | 
					                .replaceAll(/\r\n/g, ' ')
 | 
				
			||||||
 | 
					                .trim()
 | 
				
			||||||
 | 
					                .split(/\s+/);
 | 
				
			||||||
 | 
					            let withDb = t[0].split('.');
 | 
				
			||||||
 | 
					            // 表名是 db名.表名
 | 
				
			||||||
 | 
					            let tName = withDb.length > 1 ? withDb[1] : withDb[0];
 | 
				
			||||||
 | 
					            let dbName = withDb.length > 1 ? withDb[0] : db || '';
 | 
				
			||||||
 | 
					            if (t.length == 2) {
 | 
				
			||||||
 | 
					                // 表别名:表名
 | 
				
			||||||
 | 
					                result[t[1]] = { tableName: tName, dbName };
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // 只有表名无别名 取第一个无别名的表为默认表
 | 
				
			||||||
 | 
					                !defName && (defResult = { tableName: tName, dbName: db });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result[alias] || defResult;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,9 @@ func (m *Mysql) Default() {
 | 
				
			|||||||
	if m.MaxIdleConns == 0 {
 | 
						if m.MaxIdleConns == 0 {
 | 
				
			||||||
		m.MaxIdleConns = 5
 | 
							m.MaxIdleConns = 5
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if m.MaxOpenConns == 0 {
 | 
				
			||||||
 | 
							m.MaxOpenConns = m.MaxIdleConns
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Mysql) Dsn() string {
 | 
					func (m *Mysql) Dsn() string {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,7 @@ func NewClientManager() (clientManager *ClientManager) {
 | 
				
			|||||||
// 管道处理程序
 | 
					// 管道处理程序
 | 
				
			||||||
func (manager *ClientManager) Start() {
 | 
					func (manager *ClientManager) Start() {
 | 
				
			||||||
	manager.HeartbeatTimer()
 | 
						manager.HeartbeatTimer()
 | 
				
			||||||
	go manager.WriteMessage()
 | 
						manager.WriteMessage()
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
		case client := <-manager.ConnectChan:
 | 
							case client := <-manager.ConnectChan:
 | 
				
			||||||
@@ -118,7 +118,7 @@ func (manager *ClientManager) HeartbeatTimer() {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
				if err := cli.Ping(); err != nil {
 | 
									if err := cli.Ping(); err != nil {
 | 
				
			||||||
					manager.CloseClient(cli)
 | 
										manager.CloseClient(cli)
 | 
				
			||||||
					logx.Errorf("WS发送心跳失败: %v 总连接数:%d", userId, Manager.Count())
 | 
										logx.Debugf("WS发送心跳失败: %v 总连接数:%d", userId, Manager.Count())
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					logx.Debugf("WS发送心跳成功: uid=%v", userId)
 | 
										logx.Debugf("WS发送心跳成功: uid=%v", userId)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user