mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
feat: 初步移除codemirror
This commit is contained in:
@@ -10,7 +10,6 @@
|
|||||||
"@element-plus/icons-vue": "^2.0.9",
|
"@element-plus/icons-vue": "^2.0.9",
|
||||||
"asciinema-player": "^3.0.1",
|
"asciinema-player": "^3.0.1",
|
||||||
"axios": "^1.1.2",
|
"axios": "^1.1.2",
|
||||||
"codemirror": "^5.65.5",
|
|
||||||
"countup.js": "^2.0.7",
|
"countup.js": "^2.0.7",
|
||||||
"cropperjs": "^1.5.11",
|
"cropperjs": "^1.5.11",
|
||||||
"echarts": "^5.3.3",
|
"echarts": "^5.3.3",
|
||||||
|
|||||||
4
mayfly_go_web/shim.d.ts
vendored
4
mayfly_go_web/shim.d.ts
vendored
@@ -4,7 +4,7 @@ declare module '*.vue' {
|
|||||||
const component: DefineComponent<{}, {}, any>;
|
const component: DefineComponent<{}, {}, any>;
|
||||||
export default component;
|
export default component;
|
||||||
}
|
}
|
||||||
declare module 'codemirror';
|
|
||||||
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';
|
||||||
@@ -1,360 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="in-coder-panel">
|
|
||||||
<textarea ref="textarea"></textarea>
|
|
||||||
<el-select v-if="canChangeMode" class="code-mode-select" v-model="mode" @change="changeMode">
|
|
||||||
<el-option v-for="mode in modes" :key="mode.value" :label="mode.label" :value="mode.value"> </el-option>
|
|
||||||
</el-select>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { ref, nextTick, toRefs, reactive, watch, onMounted, defineComponent } from 'vue';
|
|
||||||
// 引入全局实例
|
|
||||||
import _CodeMirror from 'codemirror';
|
|
||||||
|
|
||||||
// 核心样式
|
|
||||||
import 'codemirror/lib/codemirror.css';
|
|
||||||
// 引入主题后还需要在 options 中指定主题才会生效
|
|
||||||
import 'codemirror/theme/cobalt.css';
|
|
||||||
import 'codemirror/addon/selection/active-line.js';
|
|
||||||
// 匹配括号
|
|
||||||
import 'codemirror/addon/edit/matchbrackets.js';
|
|
||||||
import 'codemirror/addon/selection/active-line';
|
|
||||||
import 'codemirror/addon/comment/comment';
|
|
||||||
|
|
||||||
// 需要引入具体的语法高亮库才会有对应的语法高亮效果
|
|
||||||
// codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库
|
|
||||||
// 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ,所以此处才把对应的 JS 提前引入
|
|
||||||
import 'codemirror/mode/yaml/yaml.js';
|
|
||||||
import 'codemirror/mode/dockerfile/dockerfile.js';
|
|
||||||
import 'codemirror/mode/nginx/nginx.js';
|
|
||||||
import 'codemirror/mode/javascript/javascript.js';
|
|
||||||
import 'codemirror/mode/css/css.js';
|
|
||||||
import 'codemirror/mode/xml/xml.js';
|
|
||||||
import 'codemirror/mode/markdown/markdown.js';
|
|
||||||
import 'codemirror/mode/python/python.js';
|
|
||||||
import 'codemirror/mode/shell/shell.js';
|
|
||||||
import 'codemirror/mode/sql/sql.js';
|
|
||||||
import 'codemirror/mode/vue/vue.js';
|
|
||||||
import 'codemirror/mode/textile/textile.js';
|
|
||||||
import 'codemirror/addon/hint/show-hint.css';
|
|
||||||
import 'codemirror/addon/hint/show-hint.js';
|
|
||||||
|
|
||||||
import { ElOption, ElSelect } from 'element-plus';
|
|
||||||
|
|
||||||
// 尝试获取全局实例
|
|
||||||
const CodeMirror = (window as any).CodeMirror || _CodeMirror;
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'CodeMirror',
|
|
||||||
components: {
|
|
||||||
ElOption,
|
|
||||||
ElSelect,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
language: {
|
|
||||||
type: String,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: String,
|
|
||||||
default: '500px',
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: String,
|
|
||||||
default: 'auto',
|
|
||||||
},
|
|
||||||
canChangeMode: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Object,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props: any, { emit }) {
|
|
||||||
let { modelValue, language } = toRefs(props);
|
|
||||||
const textarea: any = ref(null);
|
|
||||||
// 编辑器实例
|
|
||||||
let coder = null as any;
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
coder: null as any,
|
|
||||||
content: '',
|
|
||||||
// 默认的语法类型
|
|
||||||
mode: 'x-sh',
|
|
||||||
// 默认配置
|
|
||||||
options: {
|
|
||||||
// 缩进格式
|
|
||||||
tabSize: 2,
|
|
||||||
// 主题,对应主题库 JS 需要提前引入
|
|
||||||
theme: 'cobalt',
|
|
||||||
// 显示行号
|
|
||||||
lineNumbers: true,
|
|
||||||
line: true,
|
|
||||||
indentWithTabs: true,
|
|
||||||
smartIndent: true,
|
|
||||||
matchBrackets: true,
|
|
||||||
autofocus: true,
|
|
||||||
styleSelectedText: true,
|
|
||||||
styleActiveLine: true, // 高亮选中行
|
|
||||||
foldGutter: true, // 块槽
|
|
||||||
// extraKeys: { Tab: 'autocomplete' }, // 自定义快捷键
|
|
||||||
hintOptions: {
|
|
||||||
// 当匹配只有一项的时候是否自动补全
|
|
||||||
completeSingle: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// 支持切换的语法高亮类型,对应 JS 已经提前引入
|
|
||||||
// 使用的是 MIME-TYPE ,不过作为前缀的 text/ 在后面指定时写死了
|
|
||||||
modes: [
|
|
||||||
{
|
|
||||||
value: 'x-sh',
|
|
||||||
label: 'Shell',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'x-yaml',
|
|
||||||
label: 'Yaml',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'x-dockerfile',
|
|
||||||
label: 'Dockerfile',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'x-nginx-conf',
|
|
||||||
label: 'Nginx',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'html',
|
|
||||||
label: 'XML/HTML',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'x-python',
|
|
||||||
label: 'Python',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'x-sql',
|
|
||||||
label: 'SQL',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'css',
|
|
||||||
label: 'CSS',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'javascript',
|
|
||||||
label: 'Javascript',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'x-java',
|
|
||||||
label: 'Java',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'x-vue',
|
|
||||||
label: 'Vue',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'markdown',
|
|
||||||
label: 'Markdown',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'text/x-textile',
|
|
||||||
label: 'text',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
init();
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(newValue) => {
|
|
||||||
handerCodeChange(newValue);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// watch(
|
|
||||||
// () => props.options,
|
|
||||||
// (newValue, oldValue) => {
|
|
||||||
// for (const key in newValue) {
|
|
||||||
// coder.setOption(key, newValue[key]);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
const init = () => {
|
|
||||||
if (props.options) {
|
|
||||||
state.options = props.options;
|
|
||||||
}
|
|
||||||
// 初始化编辑器实例,传入需要被实例化的文本域对象和默认配置
|
|
||||||
coder = CodeMirror.fromTextArea(textarea.value, state.options);
|
|
||||||
coder.setValue(modelValue.value || state.content);
|
|
||||||
|
|
||||||
// 支持双向绑定
|
|
||||||
coder.on('change', (coder: any) => {
|
|
||||||
state.content = coder.getDoc().getValue();
|
|
||||||
emit('update:modelValue', state.content);
|
|
||||||
});
|
|
||||||
|
|
||||||
coder.on('inputRead', (instance: any, changeObj: any) => {
|
|
||||||
if (/^[a-zA-Z]/.test(changeObj.text[0])) {
|
|
||||||
instance.showHint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
coder.setSize(props.width, props.height);
|
|
||||||
// editor.setSize('width','height');
|
|
||||||
|
|
||||||
// 修改编辑器的语法配置
|
|
||||||
setMode(language.value);
|
|
||||||
|
|
||||||
[
|
|
||||||
'scroll',
|
|
||||||
'changes',
|
|
||||||
'beforeChange',
|
|
||||||
'cursorActivity',
|
|
||||||
'keyHandled',
|
|
||||||
'inputRead',
|
|
||||||
'electricInput',
|
|
||||||
'beforeSelectionChange',
|
|
||||||
'viewportChange',
|
|
||||||
'swapDoc',
|
|
||||||
'gutterClick',
|
|
||||||
'gutterContextMenu',
|
|
||||||
'focus',
|
|
||||||
'blur',
|
|
||||||
'refresh',
|
|
||||||
'optionChange',
|
|
||||||
'scrollCursorIntoView',
|
|
||||||
'update',
|
|
||||||
].forEach((event) => {
|
|
||||||
// 循环事件,并兼容 run-time 事件命名
|
|
||||||
coder.on(event, (...args: any) => {
|
|
||||||
// console.log('当有事件触发了', event, args);
|
|
||||||
emit(event, ...args);
|
|
||||||
const lowerCaseEvent = event.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
||||||
if (lowerCaseEvent !== event) {
|
|
||||||
emit(lowerCaseEvent, ...args);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
state.coder = coder;
|
|
||||||
// 不加无法显示内容,需点击后才可显示
|
|
||||||
refresh();
|
|
||||||
};
|
|
||||||
|
|
||||||
const refresh = () => {
|
|
||||||
nextTick(() => {
|
|
||||||
coder.refresh();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 设置模式
|
|
||||||
const setMode = (val: string) => {
|
|
||||||
if (val) {
|
|
||||||
// 获取具体的语法类型对象
|
|
||||||
let modeObj = getLanguage(val);
|
|
||||||
// 判断父容器传入的语法是否被支持
|
|
||||||
if (modeObj) {
|
|
||||||
state.mode = modeObj.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 修改编辑器的语法配置
|
|
||||||
coder.setOption('mode', `text/${state.mode}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取当前语法类型
|
|
||||||
const getLanguage = (language: string) => {
|
|
||||||
// 在支持的语法类型列表中寻找传入的语法类型
|
|
||||||
return state.modes.find((mode: any) => {
|
|
||||||
// 所有的值都忽略大小写,方便比较
|
|
||||||
let currentLanguage = language.toLowerCase();
|
|
||||||
let currentLabel = mode.label.toLowerCase();
|
|
||||||
let currentValue = mode.value.toLowerCase();
|
|
||||||
|
|
||||||
// 由于真实值可能不规范,例如 java 的真实值是 x-java ,所以讲 value 和 label 同时和传入语法进行比较
|
|
||||||
return currentLabel === currentLanguage || currentValue === currentLanguage;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 更改模式
|
|
||||||
const changeMode = (val: string) => {
|
|
||||||
setMode(val);
|
|
||||||
// 获取修改后的语法
|
|
||||||
let label = (getLanguage(val) as any).label.toLowerCase();
|
|
||||||
|
|
||||||
// 允许父容器通过以下函数监听当前的语法值
|
|
||||||
emit('language-change', label);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handerCodeChange = (newVal: string) => {
|
|
||||||
const cm_value = coder.getValue();
|
|
||||||
if (newVal !== cm_value) {
|
|
||||||
const scrollInfo = coder.getScrollInfo();
|
|
||||||
coder.setValue(newVal);
|
|
||||||
state.content = newVal;
|
|
||||||
coder.scrollTo(scrollInfo.left, scrollInfo.top);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
textarea,
|
|
||||||
changeMode,
|
|
||||||
refresh,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.in-coder-panel {
|
|
||||||
flex-grow: 1;
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
|
||||||
.CodeMirror {
|
|
||||||
flex-grow: 1;
|
|
||||||
z-index: 1;
|
|
||||||
.CodeMirror-code {
|
|
||||||
line-height: 19px;
|
|
||||||
}
|
|
||||||
font-family: 'JetBrainsMono';
|
|
||||||
}
|
|
||||||
.code-mode-select {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 2;
|
|
||||||
right: 10px;
|
|
||||||
top: 10px;
|
|
||||||
max-width: 130px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.CodeMirror-hints {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10000;
|
|
||||||
overflow: hidden;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
margin: 0;
|
|
||||||
padding: 2px;
|
|
||||||
|
|
||||||
-webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
|
||||||
-moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
|
||||||
box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 1px solid silver;
|
|
||||||
|
|
||||||
background: white;
|
|
||||||
font-size: 90%;
|
|
||||||
font-family: 'JetBrainsMono';
|
|
||||||
|
|
||||||
max-height: 20em;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import _CodeMirror from 'codemirror'
|
|
||||||
import codemirror from './codemirror.vue'
|
|
||||||
|
|
||||||
const CodeMirror = window.CodeMirror || _CodeMirror
|
|
||||||
const install = (Vue, config) => {
|
|
||||||
if (config) {
|
|
||||||
if (config.options) {
|
|
||||||
codemirror.props.globalOptions.default = () => config.options
|
|
||||||
}
|
|
||||||
if (config.events) {
|
|
||||||
codemirror.props.globalEvents.default = () => config.events
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vue.component(codemirror.name, codemirror)
|
|
||||||
}
|
|
||||||
|
|
||||||
const VueCodemirror = { CodeMirror, codemirror, install }
|
|
||||||
|
|
||||||
export default VueCodemirror
|
|
||||||
export { CodeMirror, codemirror, install }
|
|
||||||
209
mayfly_go_web/src/components/monaco/MonacoEditor.vue
Normal file
209
mayfly_go_web/src/components/monaco/MonacoEditor.vue
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
<template>
|
||||||
|
<div class="monaco-editor">
|
||||||
|
<div ref="monacoTextarea" :style="{ height: height }"></div>
|
||||||
|
<el-select v-if="canChangeMode" class="code-mode-select" v-model="languageMode" @change="changeLanguage">
|
||||||
|
<el-option v-for="mode in languages" :key="mode.value" :label="mode.label" :value="mode.value"> </el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, toRefs, reactive, onMounted } from 'vue';
|
||||||
|
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker';
|
||||||
|
import * as monaco from 'monaco-editor';
|
||||||
|
import { editor } from 'monaco-editor';
|
||||||
|
|
||||||
|
// 主题仓库 https://github.com/brijeshb42/monaco-themes
|
||||||
|
// 主题例子 https://editor.bitwiser.in/
|
||||||
|
// import Monokai from 'monaco-themes/themes/Monokai.json'
|
||||||
|
// import Active4D from 'monaco-themes/themes/Active4D.json'
|
||||||
|
// import ahe from 'monaco-themes/themes/All Hallows Eve.json'
|
||||||
|
// import bop from 'monaco-themes/themes/Birds of Paradise.json'
|
||||||
|
// import krTheme from 'monaco-themes/themes/krTheme.json'
|
||||||
|
// import Dracula from 'monaco-themes/themes/Dracula.json'
|
||||||
|
import SolarizedLight from 'monaco-themes/themes/Solarized-light.json'
|
||||||
|
|
||||||
|
import { ElOption, ElSelect } from 'element-plus';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '500px',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto',
|
||||||
|
},
|
||||||
|
canChangeMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
//定义事件
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const languages = [
|
||||||
|
{
|
||||||
|
value: 'shell',
|
||||||
|
label: 'Shell',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'yaml',
|
||||||
|
label: 'Yaml',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'dockerfile',
|
||||||
|
label: 'Dockerfile',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'x-nginx-conf',
|
||||||
|
label: 'Nginx',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'html',
|
||||||
|
label: 'XML/HTML',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'python',
|
||||||
|
label: 'Python',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'sql',
|
||||||
|
label: 'SQL',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'css',
|
||||||
|
label: 'CSS',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'javascript',
|
||||||
|
label: 'Javascript',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'json',
|
||||||
|
label: 'Json',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'java',
|
||||||
|
label: 'Java',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'markdown',
|
||||||
|
label: 'Markdown',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'text',
|
||||||
|
label: 'text',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
languageMode: 'shell',
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
languageMode,
|
||||||
|
} = toRefs(state)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
state.languageMode = props.language
|
||||||
|
initMonacoEditor();
|
||||||
|
setEditorValue(props.modelValue)
|
||||||
|
});
|
||||||
|
|
||||||
|
const monacoTextarea: any = ref(null);
|
||||||
|
let monacoEditor: editor.IStandaloneCodeEditor = null;
|
||||||
|
|
||||||
|
self.MonacoEnvironment = {
|
||||||
|
getWorker() {
|
||||||
|
return new EditorWorker();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const initMonacoEditor = () => {
|
||||||
|
console.log('初始化monaco编辑器')
|
||||||
|
// options参数参考 https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html#language
|
||||||
|
// 初始化一些主题
|
||||||
|
monaco.editor.defineTheme('SolarizedLight', SolarizedLight);
|
||||||
|
// monaco.editor.defineTheme('Monokai', Monokai);
|
||||||
|
// monaco.editor.defineTheme('Active4D', Active4D);
|
||||||
|
// monaco.editor.defineTheme('ahe', ahe);
|
||||||
|
// monaco.editor.defineTheme('bop', bop);
|
||||||
|
// monaco.editor.defineTheme('krTheme', krTheme);
|
||||||
|
// monaco.editor.defineTheme('Dracula', Dracula);
|
||||||
|
// monaco.editor.defineTheme('TextmateMac', TextmateMac);
|
||||||
|
|
||||||
|
monacoEditor = monaco.editor.create(monacoTextarea.value, {
|
||||||
|
language: state.languageMode,
|
||||||
|
theme: 'SolarizedLight',
|
||||||
|
automaticLayout: true, //自适应宽高布局
|
||||||
|
foldingStrategy: 'indentation',//代码可分小段折叠
|
||||||
|
roundedSelection: false, // 禁用选择文本背景的圆角
|
||||||
|
matchBrackets: 'near',
|
||||||
|
linkedEditing: true,
|
||||||
|
cursorBlinking: 'smooth',// 光标闪烁样式
|
||||||
|
mouseWheelZoom: true, // 在按住Ctrl键的同时使用鼠标滚轮时,在编辑器中缩放字体
|
||||||
|
overviewRulerBorder: false, // 不要滚动条的边框
|
||||||
|
tabSize: 2, // tab 缩进长度
|
||||||
|
fontFamily: 'JetBrainsMono', // 字体 暂时不要设置,否则光标容易错位
|
||||||
|
fontWeight: 'bold',
|
||||||
|
// fontSize: 12,
|
||||||
|
// letterSpacing: 1, 字符间距
|
||||||
|
// quickSuggestions:false, // 禁用代码提示
|
||||||
|
minimap: {
|
||||||
|
enabled: false, // 不要小地图
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听内容改变,双向绑定
|
||||||
|
monacoEditor.onDidChangeModelContent(() => {
|
||||||
|
emit('update:modelValue', monacoEditor.getModel().getValue());
|
||||||
|
})
|
||||||
|
|
||||||
|
// 动态设置主题
|
||||||
|
// monaco.editor.setTheme('hc-black');
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeLanguage = (value: any) => {
|
||||||
|
console.log('change lan');
|
||||||
|
// 获取当前的文档模型
|
||||||
|
let oldModel = monacoEditor.getModel()
|
||||||
|
// 创建一个新的文档模型
|
||||||
|
let newModel = monaco.editor.createModel(oldModel.getValue(), value)
|
||||||
|
// 设置成新的
|
||||||
|
monacoEditor.setModel(newModel)
|
||||||
|
// 销毁旧的模型
|
||||||
|
if (oldModel) {
|
||||||
|
oldModel.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setEditorValue = (value: any) => {
|
||||||
|
monacoEditor.getModel().setValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.monaco-editor {
|
||||||
|
.code-mode-select {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
max-width: 130px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -87,10 +87,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="float: right" class="fl">
|
<div style="float: right" class="fl">
|
||||||
<el-select v-model="monacoOptions.theme" placeholder="切换编辑器主题" @change="changeEditorTheme"
|
<el-select v-model="monacoOptions.theme" placeholder="切换编辑器主题"
|
||||||
filterable allow-create default-first-option size="small" class="mr10">
|
@change="changeEditorTheme" filterable allow-create default-first-option
|
||||||
<el-option v-for="item in monacoOptions.defaultThemes as string" :key="item" :label="item"
|
size="small" class="mr10">
|
||||||
:value="item">
|
<el-option v-for="item in monacoOptions.defaultThemes as string" :key="item"
|
||||||
|
:label="item" :value="item">
|
||||||
{{ item }}
|
{{ item }}
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
@@ -111,10 +112,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt5 sqlEditor">
|
<div class="mt5 sqlEditor">
|
||||||
<div ref="monacoTextarea" :style="{height: monacoOptions.height}"></div>
|
<div ref="monacoTextarea" :style="{ height: monacoOptions.height }"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="editor-move-resize" @mousedown="onDragSetHeight">
|
<div class="editor-move-resize" @mousedown="onDragSetHeight">
|
||||||
<el-icon><Minus /></el-icon>
|
<el-icon>
|
||||||
|
<Minus />
|
||||||
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt5">
|
<div class="mt5">
|
||||||
<el-row>
|
<el-row>
|
||||||
@@ -129,8 +132,8 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
<el-table @cell-dblclick="cellClick" @selection-change="onDataSelectionChange"
|
<el-table @cell-dblclick="cellClick" @selection-change="onDataSelectionChange"
|
||||||
:data="queryTab.execRes.data" v-loading="queryTab.loading" element-loading-text="查询中..."
|
:data="queryTab.execRes.data" v-loading="queryTab.loading" element-loading-text="查询中..."
|
||||||
size="small" :max-height="monacoOptions.tableMaxHeight" empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改"
|
size="small" :max-height="monacoOptions.tableMaxHeight"
|
||||||
stripe border class="mt5">
|
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改" stripe border class="mt5">
|
||||||
<el-table-column v-if="queryTab.execRes.tableColumn.length > 0 && queryTab.nowTableName"
|
<el-table-column v-if="queryTab.execRes.tableColumn.length > 0 && queryTab.nowTableName"
|
||||||
type="selection" width="35" />
|
type="selection" width="35" />
|
||||||
<el-table-column min-width="100" :width="flexColumnWidth(item, queryTab.execRes.data)"
|
<el-table-column min-width="100" :width="flexColumnWidth(item, queryTab.execRes.data)"
|
||||||
@@ -139,7 +142,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
@@ -254,44 +257,44 @@
|
|||||||
import { onMounted, toRefs, reactive, ref, watch } from 'vue';
|
import { onMounted, toRefs, reactive, ref, 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 {tagApi} from '../tag/api.ts';
|
import { tagApi } from '../tag/api.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/
|
||||||
import Monokai from 'monaco-themes/themes/Monokai.json'
|
// import Monokai from 'monaco-themes/themes/Monokai.json'
|
||||||
import Active4D from 'monaco-themes/themes/Active4D.json'
|
// import Active4D from 'monaco-themes/themes/Active4D.json'
|
||||||
import ahe from 'monaco-themes/themes/All Hallows Eve.json'
|
// import ahe from 'monaco-themes/themes/All Hallows Eve.json'
|
||||||
import bop from 'monaco-themes/themes/Birds of Paradise.json'
|
// import bop from 'monaco-themes/themes/Birds of Paradise.json'
|
||||||
import krTheme from 'monaco-themes/themes/krTheme.json'
|
// import krTheme from 'monaco-themes/themes/krTheme.json'
|
||||||
import Dracula from 'monaco-themes/themes/Dracula.json'
|
// import Dracula from 'monaco-themes/themes/Dracula.json'
|
||||||
import TextmateMac from 'monaco-themes/themes/Textmate (Mac Classic).json'
|
import SolarizedLight from 'monaco-themes/themes/Solarized-light.json'
|
||||||
|
// import TextmateMac from 'monaco-themes/themes/Textmate (Mac Classic).json'
|
||||||
import { Minus } from '@element-plus/icons-vue';
|
import { Minus } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const monacoTextarea: any = ref(null);
|
const monacoTextarea: any = ref(null);
|
||||||
const token = getSession('token');
|
const token = getSession('token');
|
||||||
const tableMap = new Map();
|
const tableMap = new Map();
|
||||||
|
|
||||||
const defalutLimit = 20
|
const defalutLimit = 20
|
||||||
|
|
||||||
export type TableMeta = {
|
type TableMeta = {
|
||||||
// 表名
|
// 表名
|
||||||
tableName:string,
|
tableName: string,
|
||||||
// 表注释
|
// 表注释
|
||||||
tableComment:string
|
tableComment: string
|
||||||
}
|
}
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
token: token,
|
token: token,
|
||||||
@@ -317,16 +320,16 @@ const state = reactive({
|
|||||||
// 点击执行按钮执行结果信息
|
// 点击执行按钮执行结果信息
|
||||||
execRes: {
|
execRes: {
|
||||||
data: [],
|
data: [],
|
||||||
tableColumn: []
|
tableColumn: []
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
nowTableName: '', //当前表格数据操作的数据库表名,用于双击编辑表内容使用
|
nowTableName: '', //当前表格数据操作的数据库表名,用于双击编辑表内容使用
|
||||||
selectionDatas: []
|
selectionDatas: []
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
tagPath: null
|
tagPath: null
|
||||||
},
|
},
|
||||||
conditionDialog: {
|
conditionDialog: {
|
||||||
title: '',
|
title: '',
|
||||||
@@ -335,19 +338,19 @@ const state = reactive({
|
|||||||
dataTab: null,
|
dataTab: null,
|
||||||
visible: false,
|
visible: false,
|
||||||
condition: '=',
|
condition: '=',
|
||||||
value: null
|
value: null
|
||||||
},
|
},
|
||||||
genSqlDialog: {
|
genSqlDialog: {
|
||||||
visible: false,
|
visible: false,
|
||||||
sql: '',
|
sql: '',
|
||||||
},
|
},
|
||||||
monacoOptions: {
|
monacoOptions: {
|
||||||
editor: {} as editor.IStandaloneCodeEditor,
|
editor: {} as editor.IStandaloneCodeEditor,
|
||||||
height: '',
|
height: '',
|
||||||
tableMaxHeight:250,
|
tableMaxHeight: 250,
|
||||||
dbTables:{},
|
dbTables: {},
|
||||||
theme:'',
|
theme: 'SolarizedLight',
|
||||||
defaultThemes:[ 'vs' ,'vs-dark', 'hc-black', 'hc-light', 'Monokai', 'Active4D', 'ahe', 'bop', 'krTheme', 'Dracula', 'TextmateMac'],
|
defaultThemes: ['SolarizedLight', 'vs', 'vs-dark'],
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const {
|
const {
|
||||||
@@ -382,23 +385,32 @@ self.MonacoEnvironment = {
|
|||||||
const initMonacoEditor = () => {
|
const initMonacoEditor = () => {
|
||||||
console.log('初始化编辑器')
|
console.log('初始化编辑器')
|
||||||
// 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
|
||||||
|
|
||||||
let defVal = `-- monaco editor`;
|
// 初始化一些主题
|
||||||
|
|
||||||
|
monaco.editor.defineTheme('SolarizedLight', SolarizedLight);
|
||||||
|
// monaco.editor.defineTheme('Monokai', Monokai);
|
||||||
|
// monaco.editor.defineTheme('Active4D', Active4D);
|
||||||
|
// monaco.editor.defineTheme('ahe', ahe);
|
||||||
|
// monaco.editor.defineTheme('bop', bop);
|
||||||
|
// monaco.editor.defineTheme('krTheme', krTheme);
|
||||||
|
// monaco.editor.defineTheme('Dracula', Dracula);
|
||||||
|
// monaco.editor.defineTheme('TextmateMac', TextmateMac);
|
||||||
|
|
||||||
monacoEditor = monaco.editor.create(monacoTextarea.value, {
|
monacoEditor = monaco.editor.create(monacoTextarea.value, {
|
||||||
value: defVal,
|
|
||||||
language: 'sql',
|
language: 'sql',
|
||||||
theme: 'vs',
|
theme: state.monacoOptions.theme,
|
||||||
automaticLayout: true, //自适应宽高布局
|
automaticLayout: true, //自适应宽高布局
|
||||||
foldingStrategy: 'indentation',//代码可分小段折叠
|
foldingStrategy: 'indentation',//代码可分小段折叠
|
||||||
roundedSelection: false, // 禁用选择文本背景的圆角
|
roundedSelection: false, // 禁用选择文本背景的圆角
|
||||||
matchBrackets: 'near',
|
matchBrackets: 'near',
|
||||||
linkedEditing:true,
|
linkedEditing: true,
|
||||||
cursorBlinking: 'smooth',// 光标闪烁样式
|
cursorBlinking: 'smooth',// 光标闪烁样式
|
||||||
mouseWheelZoom: true, // 在按住Ctrl键的同时使用鼠标滚轮时,在编辑器中缩放字体
|
mouseWheelZoom: true, // 在按住Ctrl键的同时使用鼠标滚轮时,在编辑器中缩放字体
|
||||||
overviewRulerBorder: false, // 不要滚动条的边框
|
overviewRulerBorder: false, // 不要滚动条的边框
|
||||||
tabSize: 2, // tab 缩进长度
|
tabSize: 2, // tab 缩进长度
|
||||||
// fontFamily:'consolas', // 字体 暂时不要设置,否则光标容易错位
|
fontFamily: 'JetBrainsMono', // 字体 暂时不要设置,否则光标容易错位
|
||||||
|
fontWeight: 'bold',
|
||||||
// letterSpacing: 1, 字符间距
|
// letterSpacing: 1, 字符间距
|
||||||
// quickSuggestions:false, // 禁用代码提示
|
// quickSuggestions:false, // 禁用代码提示
|
||||||
minimap: {
|
minimap: {
|
||||||
@@ -406,41 +418,32 @@ const initMonacoEditor = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始化一些主题
|
|
||||||
monaco.editor.defineTheme('Monokai', Monokai);
|
|
||||||
monaco.editor.defineTheme('Active4D', Active4D);
|
|
||||||
monaco.editor.defineTheme('ahe', ahe);
|
|
||||||
monaco.editor.defineTheme('bop', bop);
|
|
||||||
monaco.editor.defineTheme('krTheme', krTheme);
|
|
||||||
monaco.editor.defineTheme('Dracula', Dracula);
|
|
||||||
monaco.editor.defineTheme('TextmateMac', TextmateMac);
|
|
||||||
|
|
||||||
// 动态设置主题
|
// 动态设置主题
|
||||||
// monaco.editor.setTheme('hc-black');
|
// monaco.editor.setTheme('hc-black');
|
||||||
|
|
||||||
// 参考 https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-completion-provider-example
|
// 参考 https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-completion-provider-example
|
||||||
monaco.languages.registerCompletionItemProvider('sql', {
|
monaco.languages.registerCompletionItemProvider('sql', {
|
||||||
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);
|
||||||
const {lineNumber, column} = position
|
const { lineNumber, column } = position
|
||||||
const {startColumn, endColumn} = word
|
const { startColumn, endColumn } = word
|
||||||
|
|
||||||
// 当前行文本
|
// 当前行文本
|
||||||
let lineContent = model.getLineContent(lineNumber);
|
let lineContent = model.getLineContent(lineNumber);
|
||||||
// 注释行不需要代码提示
|
// 注释行不需要代码提示
|
||||||
if(lineContent.startsWith('--')){
|
if (lineContent.startsWith('--')) {
|
||||||
return {suggestions: []}
|
return { suggestions: [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
let range = {
|
let range = {
|
||||||
startLineNumber: lineNumber,
|
startLineNumber: lineNumber,
|
||||||
endLineNumber: lineNumber,
|
endLineNumber: lineNumber,
|
||||||
startColumn,
|
startColumn,
|
||||||
endColumn,
|
endColumn,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 光标前文本
|
// 光标前文本
|
||||||
const textBeforePointer = model.getValueInRange({
|
const textBeforePointer = model.getValueInRange({
|
||||||
startLineNumber: lineNumber,
|
startLineNumber: lineNumber,
|
||||||
@@ -466,9 +469,9 @@ const initMonacoEditor = () => {
|
|||||||
const tokens = textBeforePointer.trim().split(/\s+/)
|
const tokens = textBeforePointer.trim().split(/\s+/)
|
||||||
const lastToken = tokens[tokens.length - 1].toLowerCase()
|
const lastToken = tokens[tokens.length - 1].toLowerCase()
|
||||||
|
|
||||||
console.log("光标前文本:=>" + textBeforePointerMulti)
|
// console.log("光标前文本:=>" + textBeforePointerMulti)
|
||||||
|
|
||||||
console.log("最后输入的:=>" + lastToken)
|
// console.log("最后输入的:=>" + lastToken)
|
||||||
if (lastToken.endsWith('.')) {
|
if (lastToken.endsWith('.')) {
|
||||||
// 如果是.触发代码提示,则进行【 库.表名联想 】 或 【 表别名.表字段联想 】
|
// 如果是.触发代码提示,则进行【 库.表名联想 】 或 【 表别名.表字段联想 】
|
||||||
let str = lastToken.substring(0, lastToken.lastIndexOf('.'))
|
let str = lastToken.substring(0, lastToken.lastIndexOf('.'))
|
||||||
@@ -476,52 +479,50 @@ const initMonacoEditor = () => {
|
|||||||
if (state.databaseList.indexOf(str) > -1) {
|
if (state.databaseList.indexOf(str) > -1) {
|
||||||
let tables = await loadTableMetadata(str)
|
let tables = await loadTableMetadata(str)
|
||||||
let suggestions: languages.CompletionItem[] = []
|
let suggestions: languages.CompletionItem[] = []
|
||||||
for(let item of tables){
|
for (let item of tables) {
|
||||||
const {tableName, tableComment} = item
|
const { tableName, tableComment } = item
|
||||||
suggestions.push({
|
suggestions.push({
|
||||||
label: tableName + ( tableComment?' - ' + tableComment :'' ),
|
label: tableName + (tableComment ? ' - ' + tableComment : ''),
|
||||||
kind: monaco.languages.CompletionItemKind.File,
|
kind: monaco.languages.CompletionItemKind.File,
|
||||||
insertText: tableName,
|
insertText: tableName,
|
||||||
range
|
range
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { suggestions }
|
return { suggestions }
|
||||||
}
|
}
|
||||||
|
|
||||||
let sql = textBeforePointerMulti.split(';')[textBeforePointerMulti.split(';').length - 1] + textAfterPointerMulti.split(';')[0];
|
let sql = textBeforePointerMulti.split(';')[textBeforePointerMulti.split(';').length - 1] + textAfterPointerMulti.split(';')[0];
|
||||||
// 表别名.表字段联想
|
// 表别名.表字段联想
|
||||||
let tableInfo = getTableByAlias(sql,state.db, str)
|
let tableInfo = getTableByAlias(sql, state.db, str)
|
||||||
if(tableInfo.tableName){
|
if (tableInfo.tableName) {
|
||||||
let table = tableInfo.tableName
|
let table = tableInfo.tableName
|
||||||
let db = tableInfo.dbName
|
let db = tableInfo.dbName
|
||||||
// 取出表名并提示
|
// 取出表名并提示
|
||||||
let dbs = state.monacoOptions.dbTables[db]
|
let dbs = state.monacoOptions.dbTables[db]
|
||||||
let tables = dbs ? (dbs[table] || []) : [];
|
let columns = dbs ? (dbs[table] || []) : [];
|
||||||
if((!tables || tables.length === 0) && db){
|
if ((!columns || columns.length === 0) && db) {
|
||||||
state.monacoOptions.dbTables[db] = await loadHintTables(db)
|
state.monacoOptions.dbTables[db] = await loadHintTables(db)
|
||||||
dbs = state.monacoOptions.dbTables[db]
|
dbs = state.monacoOptions.dbTables[db]
|
||||||
tables = dbs ? (dbs[table] || []) : [];
|
columns = dbs ? (dbs[table] || []) : [];
|
||||||
}
|
}
|
||||||
tables.sort()
|
|
||||||
let suggestions: languages.CompletionItem[] = []
|
let suggestions: languages.CompletionItem[] = []
|
||||||
tables.forEach((a:string)=>{
|
columns.forEach((a: string, index: any) => {
|
||||||
// 字段数据格式 字段名 字段注释, 如: create_time [datetime][创建时间]
|
// 字段数据格式 字段名 字段注释, 如: create_time [datetime][创建时间]
|
||||||
let fieldName = a.substring(0,a.indexOf(" "))
|
const nameAndComment = a.split(" ")
|
||||||
let comment = a.replace(eval(`/${fieldName}\\s+/`), '')
|
const fieldName = nameAndComment[0]
|
||||||
let detail = fieldName + ( comment?' - ' + comment :'' )
|
|
||||||
suggestions.push({
|
suggestions.push({
|
||||||
label: detail,
|
label: a, // [datetime][创建时间]
|
||||||
kind: monaco.languages.CompletionItemKind.Property,
|
kind: monaco.languages.CompletionItemKind.Property,
|
||||||
detail: detail,
|
detail: '', // 不显示detail, 否则选中时备注等会被遮挡
|
||||||
insertText: fieldName,
|
insertText: fieldName + ' ', // create_time
|
||||||
range
|
range,
|
||||||
|
sortText: 100 + index + '' // 使用表字段声明顺序排序
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
return { suggestions }
|
return { suggestions }
|
||||||
//
|
|
||||||
}
|
}
|
||||||
return { suggestions:[] }
|
return { suggestions: [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 库名联想
|
// 库名联想
|
||||||
|
|
||||||
@@ -570,28 +571,27 @@ const initMonacoEditor = () => {
|
|||||||
kind: monaco.languages.CompletionItemKind.Folder,
|
kind: monaco.languages.CompletionItemKind.Folder,
|
||||||
insertText: a,
|
insertText: a,
|
||||||
range
|
range
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
// 表名联想
|
// 表名联想
|
||||||
state.tableMetadata.forEach((tableMeta: TableMeta) => {
|
state.tableMetadata.forEach((tableMeta: TableMeta) => {
|
||||||
const {tableName, tableComment} = tableMeta
|
const { tableName, tableComment } = tableMeta
|
||||||
suggestions.push({
|
suggestions.push({
|
||||||
label: tableName + ' - ' + tableComment,
|
label: tableName + ' - ' + tableComment,
|
||||||
kind: monaco.languages.CompletionItemKind.File,
|
kind: monaco.languages.CompletionItemKind.File,
|
||||||
detail: tableComment,
|
detail: tableComment,
|
||||||
insertText: tableName,
|
insertText: tableName + ' ',
|
||||||
range
|
range
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
// 默认提示
|
// 默认提示
|
||||||
return {
|
return {
|
||||||
suggestions: suggestions
|
suggestions: suggestions
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -600,8 +600,8 @@ const initMonacoEditor = () => {
|
|||||||
* @param db 默认数据库
|
* @param db 默认数据库
|
||||||
* @param alias 别名
|
* @param alias 别名
|
||||||
*/
|
*/
|
||||||
const getTableByAlias = (sql: string, db: string, alias: string):{dbName: string, tableName: string} => {
|
const getTableByAlias = (sql: string, db: string, alias: string): { dbName: string, tableName: string } => {
|
||||||
|
|
||||||
// 表别名:表名
|
// 表别名:表名
|
||||||
let result = {};
|
let result = {};
|
||||||
let defName = '';
|
let defName = '';
|
||||||
@@ -617,10 +617,10 @@ where l.name='kevin' and exsits(select 1 from pharmacywestpas pw where p.outvisi
|
|||||||
unit all
|
unit all
|
||||||
select * from invisit v where`.match(/(join|from)\s+(\w*-?\w*\.?\w+)\s*(as)?\s*(\w*)/gi)
|
select * from invisit v where`.match(/(join|from)\s+(\w*-?\w*\.?\w+)\s*(as)?\s*(\w*)/gi)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let match = sql.match(/(join|from)\s+(\w*-?\w*\.?\w+)\s*(as)?\s*(\w*)/gi)
|
let match = sql.match(/(join|from)\s+(\w*-?\w*\.?\w+)\s*(as)?\s*(\w*)/gi)
|
||||||
if(match && match.length>0){
|
if (match && match.length > 0) {
|
||||||
match.forEach(a=>{
|
match.forEach(a => {
|
||||||
// 去掉前缀,取出
|
// 去掉前缀,取出
|
||||||
let t = a.substring(5, a.length)
|
let t = a.substring(5, a.length)
|
||||||
.replaceAll(/\s+as\s+/g, ' ')
|
.replaceAll(/\s+as\s+/g, ' ')
|
||||||
@@ -628,11 +628,11 @@ select * from invisit v where`.match(/(join|from)\s+(\w*-?\w*\.?\w+)\s*(as)?\s*(
|
|||||||
let withDb = t[0].split('.');
|
let withDb = t[0].split('.');
|
||||||
// 表名是 db名.表名
|
// 表名是 db名.表名
|
||||||
let tName = withDb.length > 1 ? withDb[1] : withDb[0]
|
let tName = withDb.length > 1 ? withDb[1] : withDb[0]
|
||||||
let dbName = withDb.length > 1 ? withDb[0] :(db||'')
|
let dbName = withDb.length > 1 ? withDb[0] : (db || '')
|
||||||
if(t.length == 2){
|
if (t.length == 2) {
|
||||||
// 表别名:表名
|
// 表别名:表名
|
||||||
result[t[1]]= {tableName: tName, dbName}
|
result[t[1]] = { tableName: tName, dbName }
|
||||||
}else{
|
} else {
|
||||||
// 只有表名无别名 取第一个无别名的表为默认表
|
// 只有表名无别名 取第一个无别名的表为默认表
|
||||||
!defName && (defResult = { tableName: tName, dbName: db })
|
!defName && (defResult = { tableName: tName, dbName: db })
|
||||||
}
|
}
|
||||||
@@ -652,18 +652,18 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置codemirror高度和数据表高度
|
* 设置editor高度和数据表高度
|
||||||
*/
|
*/
|
||||||
const setHeight = () => {
|
const setHeight = () => {
|
||||||
// 默认300px
|
// 默认300px
|
||||||
state.monacoOptions.height = window.innerHeight - 550 + 'px'
|
state.monacoOptions.height = window.innerHeight - 550 + 'px'
|
||||||
state.dataTabsTableHeight = window.innerHeight - 274 ;
|
state.dataTabsTableHeight = window.innerHeight - 274;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拖拽改变sql编辑区和查询结果区高度
|
* 拖拽改变sql编辑区和查询结果区高度
|
||||||
*/
|
*/
|
||||||
const onDragSetHeight = (e: any) => {
|
const onDragSetHeight = () => {
|
||||||
document.onmousemove = (e) => {
|
document.onmousemove = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
//得到鼠标拖动的宽高距离:取绝对值
|
//得到鼠标拖动的宽高距离:取绝对值
|
||||||
@@ -948,16 +948,16 @@ const getColumnTip = (tableName: string, columnName: string) => {
|
|||||||
const getSql = () => {
|
const getSql = () => {
|
||||||
let res = '' as string | undefined;
|
let res = '' as string | undefined;
|
||||||
// 编辑器还没初始化
|
// 编辑器还没初始化
|
||||||
if(!monacoEditor.getModel){
|
if (!monacoEditor.getModel) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// 选择选中的sql
|
// 选择选中的sql
|
||||||
let selection = monacoEditor.getSelection()
|
let selection = monacoEditor.getSelection()
|
||||||
if (selection){
|
if (selection) {
|
||||||
res = monacoEditor.getModel()?.getValueInRange(selection)
|
res = monacoEditor.getModel()?.getValueInRange(selection)
|
||||||
}
|
}
|
||||||
// 整个编辑器的sql
|
// 整个编辑器的sql
|
||||||
if(!res){
|
if (!res) {
|
||||||
return monacoEditor.getModel()?.getValue()
|
return monacoEditor.getModel()?.getValue()
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
@@ -982,22 +982,22 @@ const changeDb = async (db: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearDb();
|
clearDb();
|
||||||
|
|
||||||
// 加载数据库下所有表
|
// 加载数据库下所有表
|
||||||
state.tableMetadata = await loadTableMetadata(db)
|
state.tableMetadata = await loadTableMetadata(db)
|
||||||
|
|
||||||
// 加载数据库下所有表字段信息
|
// 加载数据库下所有表字段信息
|
||||||
state.monacoOptions.dbTables[db] = await loadHintTables(db)
|
state.monacoOptions.dbTables[db] = await loadHintTables(db)
|
||||||
|
|
||||||
getSqlNames();
|
getSqlNames();
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadTableMetadata = async (db: string) =>{
|
const loadTableMetadata = async (db: string) => {
|
||||||
return await dbApi.tableMetadata.request({id: state.dbId, db})
|
return await dbApi.tableMetadata.request({ id: state.dbId, db })
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadHintTables = async (db: string) =>{
|
const loadHintTables = async (db: string) => {
|
||||||
return await dbApi.hintTables.request({id: state.dbId, db,})
|
return await dbApi.hintTables.request({ id: state.dbId, db, })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选择表事件
|
// 选择表事件
|
||||||
@@ -1195,6 +1195,7 @@ const onTableSortChange = async (sort: any) => {
|
|||||||
const changeSqlTemplate = () => {
|
const changeSqlTemplate = () => {
|
||||||
getUserSql();
|
getUserSql();
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeEditorTheme = () => {
|
const changeEditorTheme = () => {
|
||||||
monaco.editor.setTheme(state.monacoOptions.theme);
|
monaco.editor.setTheme(state.monacoOptions.theme);
|
||||||
};
|
};
|
||||||
@@ -1217,10 +1218,6 @@ const setSqlEditorValue = (value: string) => {
|
|||||||
monacoEditor.getModel()?.setValue(value);
|
monacoEditor.getModel()?.setValue(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCodermirrorValue = () => {
|
|
||||||
return codemirror.getValue();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户保存的sql模板名称
|
* 获取用户保存的sql模板名称
|
||||||
*/
|
*/
|
||||||
@@ -1370,7 +1367,7 @@ const cellClick = (row: any, column: any, cell: any) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 转为字符串比较,可能存在数字等
|
// 转为字符串比较,可能存在数字等
|
||||||
let text = (row[property] || row[property]==0 ? row[property] : '') + '';
|
let text = (row[property] || row[property] == 0 ? row[property] : '') + '';
|
||||||
let div = cell.children[0];
|
let div = cell.children[0];
|
||||||
if (div) {
|
if (div) {
|
||||||
let input = document.createElement('input');
|
let input = document.createElement('input');
|
||||||
@@ -1466,13 +1463,49 @@ const addRow = async () => {
|
|||||||
* 格式化sql
|
* 格式化sql
|
||||||
*/
|
*/
|
||||||
const formatSql = () => {
|
const formatSql = () => {
|
||||||
let selectSql = getSql();
|
let selection = monacoEditor.getSelection()
|
||||||
if(selectSql){
|
let sql = monacoEditor.getModel()?.getValueInRange(selection)
|
||||||
monacoEditor.getModel()?.setValue(sqlFormatter(selectSql))
|
// 有选中sql则格式化并替换选中sql, 否则格式化编辑器所有内容
|
||||||
|
if (sql) {
|
||||||
|
replaceSelection(sqlFormatter(sql), selection)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
monacoEditor.getModel()?.setValue(sqlFormatter(monacoEditor.getValue()));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换选中的内容
|
||||||
|
*/
|
||||||
|
const replaceSelection = (str: string, selection: any) => {
|
||||||
|
if (!selection) {
|
||||||
|
monacoEditor.getModel().setValue(str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { startLineNumber, endLineNumber, startColumn, endColumn } = selection
|
||||||
|
const model = monacoEditor.getModel();
|
||||||
|
|
||||||
|
const textBeforeSelection = model.getValueInRange({
|
||||||
|
startLineNumber: 1,
|
||||||
|
startColumn: 0,
|
||||||
|
endLineNumber: startLineNumber,
|
||||||
|
endColumn: startColumn,
|
||||||
|
})
|
||||||
|
|
||||||
|
const textAfterSelection = model.getValueInRange({
|
||||||
|
startLineNumber: endLineNumber,
|
||||||
|
startColumn: endColumn,
|
||||||
|
endLineNumber: model.getLineCount(),
|
||||||
|
endColumn: model.getLineMaxColumn(model.getLineCount()),
|
||||||
|
})
|
||||||
|
|
||||||
|
monacoEditor.setValue(textBeforeSelection + str + textAfterSelection)
|
||||||
|
monacoEditor.focus()
|
||||||
|
monacoEditor.setPosition({
|
||||||
|
lineNumber: startLineNumber,
|
||||||
|
column: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const search = async () => {
|
const search = async () => {
|
||||||
const res = await dbApi.dbs.request(state.params);
|
const res = await dbApi.dbs.request(state.params);
|
||||||
state.dbs = res.list;
|
state.dbs = res.list;
|
||||||
@@ -1515,17 +1548,6 @@ watch(store.state.sqlExecInfo, async (newValue) => {
|
|||||||
font-size: 8pt;
|
font-size: 8pt;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
|
|
||||||
.CodeMirror {
|
|
||||||
flex-grow: 1;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
.CodeMirror-code {
|
|
||||||
line-height: 19px;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-family: 'JetBrainsMono';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-move-resize {
|
.editor-move-resize {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dialog title="待执行SQL" v-model="dialogVisible" :show-close="false" width="600px" @close="cancel">
|
<el-dialog :destroy-on-close="true" title="待执行SQL" v-model="dialogVisible" :show-close="false" width="600px" @close="cancel">
|
||||||
<codemirror height="350px" class="codesql" ref="cmEditor" language="sql" v-model="sqlValue"
|
<monaco-editor height="300px" class="codesql" language="sql" v-model="sqlValue" />
|
||||||
:options="cmOptions" />
|
|
||||||
<el-input ref="remarkInputRef" v-model="remark" placeholder="请输入执行备注" class="mt5" />
|
<el-input ref="remarkInputRef" v-model="remark" placeholder="请输入执行备注" class="mt5" />
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@@ -19,11 +18,7 @@ import { toRefs, ref, nextTick, reactive } from 'vue';
|
|||||||
import { dbApi } from '../api';
|
import { dbApi } from '../api';
|
||||||
import { ElDialog, ElButton, ElInput, ElMessage, InputInstance } from 'element-plus';
|
import { ElDialog, ElButton, ElInput, ElMessage, InputInstance } from 'element-plus';
|
||||||
// import base style
|
// import base style
|
||||||
import 'codemirror/lib/codemirror.css';
|
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||||
// 引入主题后还需要在 options 中指定主题才会生效
|
|
||||||
import 'codemirror/theme/base16-light.css';
|
|
||||||
import 'codemirror/addon/selection/active-line';
|
|
||||||
import { codemirror } from '@/components/codemirror';
|
|
||||||
import { format as sqlFormatter } from 'sql-formatter';
|
import { format as sqlFormatter } from 'sql-formatter';
|
||||||
|
|
||||||
import { SqlExecProps } from './SqlExecBox';
|
import { SqlExecProps } from './SqlExecBox';
|
||||||
@@ -43,19 +38,6 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const cmOptions = {
|
|
||||||
tabSize: 4,
|
|
||||||
mode: 'text/x-sql',
|
|
||||||
lineNumbers: true,
|
|
||||||
line: true,
|
|
||||||
indentWithTabs: true,
|
|
||||||
smartIndent: true,
|
|
||||||
matchBrackets: true,
|
|
||||||
theme: 'base16-light',
|
|
||||||
autofocus: true,
|
|
||||||
extraKeys: { Tab: 'autocomplete' }, // 自定义快捷键
|
|
||||||
}
|
|
||||||
|
|
||||||
const remarkInputRef = ref<InputInstance>();
|
const remarkInputRef = ref<InputInstance>();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
dialogVisible: false,
|
dialogVisible: false,
|
||||||
|
|||||||
@@ -148,11 +148,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog :destroy-on-close="true" :title="fileContent.dialogTitle" v-model="fileContent.contentVisible"
|
<el-dialog :destroy-on-close="true" :title="fileContent.dialogTitle" v-model="fileContent.contentVisible" :close-on-click-modal="false"
|
||||||
:close-on-click-modal="false" top="5vh" width="70%">
|
top="5vh" width="70%">
|
||||||
<div>
|
<div>
|
||||||
<codemirror :can-change-mode="true" ref="cmEditor" v-model="fileContent.content"
|
<monaco-editor :can-change-mode="true" v-model="fileContent.content" :language="fileContent.type" />
|
||||||
:language="fileContent.type" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -170,7 +169,7 @@ import { ref, toRefs, reactive, watch } from 'vue';
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { machineApi } from './api';
|
import { machineApi } from './api';
|
||||||
|
|
||||||
import { codemirror } from '@/components/codemirror';
|
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||||
import { getSession } from '@/common/utils/storage';
|
import { getSession } from '@/common/utils/storage';
|
||||||
import enums from './enums';
|
import enums from './enums';
|
||||||
import config from '@/common/config';
|
import config from '@/common/config';
|
||||||
@@ -343,14 +342,17 @@ const getFileType = (path: string) => {
|
|||||||
if (path.endsWith('.sh')) {
|
if (path.endsWith('.sh')) {
|
||||||
return 'shell';
|
return 'shell';
|
||||||
}
|
}
|
||||||
if (path.endsWith('js') || path.endsWith('json')) {
|
if (path.endsWith('js')) {
|
||||||
return 'javascript';
|
return 'javascript';
|
||||||
}
|
}
|
||||||
|
if (path.endsWith('json')) {
|
||||||
|
return 'json';
|
||||||
|
}
|
||||||
if (path.endsWith('Dockerfile')) {
|
if (path.endsWith('Dockerfile')) {
|
||||||
return 'dockerfile';
|
return 'dockerfile';
|
||||||
}
|
}
|
||||||
if (path.endsWith('nginx.conf')) {
|
if (path.endsWith('nginx.conf')) {
|
||||||
return 'nginx';
|
return 'shell';
|
||||||
}
|
}
|
||||||
if (path.endsWith('sql')) {
|
if (path.endsWith('sql')) {
|
||||||
return 'sql';
|
return 'sql';
|
||||||
|
|||||||
@@ -45,9 +45,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item prop="script" label="内容" id="content">
|
<monaco-editor v-model="form.script" language="shell" height="300px" />
|
||||||
<codemirror ref="cmEditor" v-model="form.script" language="shell" width="700px" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -67,8 +65,7 @@ import { ElMessage } from 'element-plus';
|
|||||||
import { machineApi } from './api';
|
import { machineApi } from './api';
|
||||||
import enums from './enums';
|
import enums from './enums';
|
||||||
import { notEmpty } from '@/common/assert';
|
import { notEmpty } from '@/common/assert';
|
||||||
|
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||||
import { codemirror } from '@/components/codemirror';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
@@ -176,9 +173,5 @@ const cancel = () => {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
#content {
|
|
||||||
.CodeMirror {
|
|
||||||
height: 300px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, toRefs, reactive, watch, defineComponent } from 'vue';
|
import { ref, toRefs, reactive, watch } from 'vue';
|
||||||
import { configApi } from '../api';
|
import { configApi } from '../api';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|||||||
@@ -96,6 +96,11 @@
|
|||||||
resolved "https://registry.npmmirror.com/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz"
|
resolved "https://registry.npmmirror.com/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz"
|
||||||
integrity sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==
|
integrity sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==
|
||||||
|
|
||||||
|
"@types/antlr4@4.7.0":
|
||||||
|
version "4.7.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/antlr4/-/antlr4-4.7.0.tgz#e6300119bddff6e23f5bbd299f5cf3c722a6249b"
|
||||||
|
integrity sha512-WdyHH4PHxBQkeWoRTbuC/dvf0QErJpJE4UpESQSRmKoMER15DCLFHAHQjkwevMKQie0kqawS/eTY563GGMbz/g==
|
||||||
|
|
||||||
"@types/json-schema@^7.0.7":
|
"@types/json-schema@^7.0.7":
|
||||||
version "7.0.9"
|
version "7.0.9"
|
||||||
resolved "https://registry.npmmirror.com/@types/json-schema/download/@types/json-schema-7.0.9.tgz?cache=0&sync_timestamp=1637266073261&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.9.tgz"
|
resolved "https://registry.npmmirror.com/@types/json-schema/download/@types/json-schema-7.0.9.tgz?cache=0&sync_timestamp=1637266073261&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.9.tgz"
|
||||||
@@ -435,6 +440,11 @@ ansi-styles@^4.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-convert "^2.0.1"
|
color-convert "^2.0.1"
|
||||||
|
|
||||||
|
antlr4@4.7.2:
|
||||||
|
version "4.7.2"
|
||||||
|
resolved "https://registry.npmmirror.com/antlr4/-/antlr4-4.7.2.tgz#9d0b5987bb63660de658055ee9149141b4d9b462"
|
||||||
|
integrity sha512-vZA1xYufXLe3LX+ja9rIVxjRmILb1x3k7KYZHltRbfJtXjJ1DlFIqt+CbPYmghx0EuzY9DajiDw+MdyEt1qAsQ==
|
||||||
|
|
||||||
anymatch@~3.1.2:
|
anymatch@~3.1.2:
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.nlark.com/anymatch/download/anymatch-3.1.2.tgz"
|
resolved "https://registry.nlark.com/anymatch/download/anymatch-3.1.2.tgz"
|
||||||
@@ -542,11 +552,6 @@ clipboard@^2.0.6:
|
|||||||
select "^1.1.2"
|
select "^1.1.2"
|
||||||
tiny-emitter "^2.0.0"
|
tiny-emitter "^2.0.0"
|
||||||
|
|
||||||
codemirror@^5.65.5:
|
|
||||||
version "5.65.5"
|
|
||||||
resolved "https://registry.npmmirror.com/codemirror/-/codemirror-5.65.5.tgz"
|
|
||||||
integrity sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w==
|
|
||||||
|
|
||||||
color-convert@^2.0.1:
|
color-convert@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.nlark.com/color-convert/download/color-convert-2.0.1.tgz"
|
resolved "https://registry.nlark.com/color-convert/download/color-convert-2.0.1.tgz"
|
||||||
@@ -646,6 +651,14 @@ dotenv@^10.0.0:
|
|||||||
resolved "https://registry.nlark.com/dotenv/download/dotenv-10.0.0.tgz"
|
resolved "https://registry.nlark.com/dotenv/download/dotenv-10.0.0.tgz"
|
||||||
integrity sha1-PUInuPuV+BCWzdK2ZlP7LHCFuoE=
|
integrity sha1-PUInuPuV+BCWzdK2ZlP7LHCFuoE=
|
||||||
|
|
||||||
|
dt-sql-parser@^4.0.0-beta.2.2:
|
||||||
|
version "4.0.0-beta.2.2"
|
||||||
|
resolved "https://registry.npmmirror.com/dt-sql-parser/-/dt-sql-parser-4.0.0-beta.2.2.tgz#84fbed385afc19ca6464cd266889e3f52e73083a"
|
||||||
|
integrity sha512-LLAE659zgizdokkDniHFPk0PsLPV3cXFOQPW+QT+3W1/TQJ2h8yzKCBBufXmKAHMpAr+KjTRTa71VJRzWJx8Zg==
|
||||||
|
dependencies:
|
||||||
|
"@types/antlr4" "4.7.0"
|
||||||
|
antlr4 "4.7.2"
|
||||||
|
|
||||||
echarts@^5.3.3:
|
echarts@^5.3.3:
|
||||||
version "5.3.3"
|
version "5.3.3"
|
||||||
resolved "https://registry.npmmirror.com/echarts/-/echarts-5.3.3.tgz"
|
resolved "https://registry.npmmirror.com/echarts/-/echarts-5.3.3.tgz"
|
||||||
@@ -982,6 +995,11 @@ fast-levenshtein@^2.0.6:
|
|||||||
resolved "https://registry.nlark.com/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz"
|
resolved "https://registry.nlark.com/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz"
|
||||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||||
|
|
||||||
|
fast-plist@^0.1.2:
|
||||||
|
version "0.1.2"
|
||||||
|
resolved "https://registry.npmmirror.com/fast-plist/-/fast-plist-0.1.2.tgz#a45aff345196006d406ca6cdcd05f69051ef35b8"
|
||||||
|
integrity sha512-2HxzrqJhmMoxVzARjYFvkzkL2dCBB8sogU5sD8gqcZWv5UCivK9/cXM9KIPDRwU+eD3mbRDN/GhW8bO/4dtMfg==
|
||||||
|
|
||||||
fastq@^1.6.0:
|
fastq@^1.6.0:
|
||||||
version "1.13.0"
|
version "1.13.0"
|
||||||
resolved "https://registry.nlark.com/fastq/download/fastq-1.13.0.tgz"
|
resolved "https://registry.nlark.com/fastq/download/fastq-1.13.0.tgz"
|
||||||
@@ -1342,6 +1360,25 @@ mobius1-selectr@^2.4.13:
|
|||||||
resolved "https://registry.npmmirror.com/mobius1-selectr/-/mobius1-selectr-2.4.13.tgz"
|
resolved "https://registry.npmmirror.com/mobius1-selectr/-/mobius1-selectr-2.4.13.tgz"
|
||||||
integrity sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==
|
integrity sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==
|
||||||
|
|
||||||
|
monaco-editor@^0.34.1:
|
||||||
|
version "0.34.1"
|
||||||
|
resolved "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.34.1.tgz#1b75c4ad6bc4c1f9da656d740d98e0b850a22f87"
|
||||||
|
integrity sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ==
|
||||||
|
|
||||||
|
monaco-sql-languages@^0.9.5:
|
||||||
|
version "0.9.5"
|
||||||
|
resolved "https://registry.npmmirror.com/monaco-sql-languages/-/monaco-sql-languages-0.9.5.tgz#075ffe947e66f0dc7a53f92cb99c2d4649632a34"
|
||||||
|
integrity sha512-IBIKQVIoW1Q90pJ/0Qi0sWMgbvho5ug17wx64hVid/XCr+L7ngJaTdaRnveOMPwg9qj+PQqOt1Ga0q0AwG85wA==
|
||||||
|
dependencies:
|
||||||
|
dt-sql-parser "^4.0.0-beta.2.2"
|
||||||
|
|
||||||
|
monaco-themes@^0.4.2:
|
||||||
|
version "0.4.2"
|
||||||
|
resolved "https://registry.npmmirror.com/monaco-themes/-/monaco-themes-0.4.2.tgz#6939339cb2f0bfb743f6e454de4136971834f16a"
|
||||||
|
integrity sha512-T3kp6SC5MPJvwYGXZENCd0UOIKVgUVV5SjsiXLBhgEZBnScY+6gEbwNRK1oYmfwbf+dGVqF1bSLN5YcrFu3HmA==
|
||||||
|
dependencies:
|
||||||
|
fast-plist "^0.1.2"
|
||||||
|
|
||||||
ms@2.1.2:
|
ms@2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.npmmirror.com/ms/download/ms-2.1.2.tgz"
|
resolved "https://registry.npmmirror.com/ms/download/ms-2.1.2.tgz"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/ctx"
|
"mayfly-go/pkg/ctx"
|
||||||
|
"mayfly-go/pkg/global"
|
||||||
"mayfly-go/pkg/ws"
|
"mayfly-go/pkg/ws"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -17,8 +18,11 @@ func (s *System) ConnectWs(g *gin.Context) {
|
|||||||
wsConn, err := ws.Upgrader.Upgrade(g.Writer, g.Request, nil)
|
wsConn, err := ws.Upgrader.Upgrade(g.Writer, g.Request, nil)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
wsConn.WriteMessage(websocket.TextMessage, []byte(err.(error).Error()))
|
global.Log.Error(err.(error).Error())
|
||||||
wsConn.Close()
|
if wsConn != nil {
|
||||||
|
wsConn.WriteMessage(websocket.TextMessage, []byte(err.(error).Error()))
|
||||||
|
wsConn.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user