feat: 统一日志组件 (#5727)

This commit is contained in:
zhengkunwang 2024-07-09 16:29:23 +08:00 committed by zhengkunwang223
parent d91ce3da65
commit f3fac23a84
9 changed files with 146 additions and 257 deletions

View file

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div style="display: flex; flex-wrap: wrap"> <div class="flex flex-wrap">
<el-select @change="searchLogs" v-model="logSearch.mode" class="selectWidth"> <el-select @change="searchLogs" v-model="logSearch.mode" class="selectWidth">
<template #prefix>{{ $t('container.fetch') }}</template> <template #prefix>{{ $t('container.fetch') }}</template>
<el-option v-for="item in timeOptions" :key="item.label" :value="item.value" :label="item.label" /> <el-option v-for="item in timeOptions" :key="item.label" :value="item.value" :label="item.label" />
@ -25,17 +25,7 @@
{{ $t('commons.button.clean') }} {{ $t('commons.button.clean') }}
</el-button> </el-button>
</div> </div>
<LogPro v-model="logInfo" :heightDiff="400"></LogPro>
<div :style="{ height: `calc(100vh - ${loadHeight()})`, 'margin-top': '10px', 'min-height': '400px' }">
<highlightjs
v-if="showLog"
ref="editorRef"
class="editor-main"
language="JavaScript"
:autodetect="false"
:code="logInfo"
></highlightjs>
</div>
</div> </div>
</template> </template>
@ -45,18 +35,10 @@ import i18n from '@/lang';
import { dateFormatForName, downloadWithContent } from '@/utils/util'; import { dateFormatForName, downloadWithContent } from '@/utils/util';
import { onBeforeUnmount, reactive, ref } from 'vue'; import { onBeforeUnmount, reactive, ref } from 'vue';
import { MsgError, MsgSuccess } from '@/utils/message'; import { MsgError, MsgSuccess } from '@/utils/message';
import { GlobalStore } from '@/store'; import LogPro from '@/components/log-pro/index.vue';
const globalStore = GlobalStore();
const logInfo = ref(); const logInfo = ref();
const terminalSocket = ref<WebSocket>(); const terminalSocket = ref<WebSocket>();
const editorRef = ref();
const scrollerElement = ref<HTMLElement | null>(null);
const showLog = ref(false);
const loadHeight = () => {
return globalStore.openMenuTabs ? '405px' : '375px';
};
const logSearch = reactive({ const logSearch = reactive({
isWatch: false, isWatch: false,
@ -102,9 +84,6 @@ const searchLogs = async () => {
); );
terminalSocket.value.onmessage = (event) => { terminalSocket.value.onmessage = (event) => {
logInfo.value += event.data; logInfo.value += event.data;
nextTick(() => {
scrollerElement.value.scrollTop = scrollerElement.value.scrollHeight;
});
}; };
}; };
@ -152,17 +131,6 @@ onBeforeUnmount(() => {
terminalSocket.value?.send('close conn'); terminalSocket.value?.send('close conn');
}); });
onMounted(async () => {
await nextTick(() => {
showLog.value = true;
});
if (editorRef.value) {
scrollerElement.value = editorRef.value.$el as HTMLElement;
let hljsDom = scrollerElement.value.querySelector('.hljs') as HTMLElement;
hljsDom.style['min-height'] = '500px';
}
});
defineExpose({ defineExpose({
acceptParams, acceptParams,
}); });

View file

@ -0,0 +1,61 @@
<template>
<highlightjs
ref="editorRef"
language="JavaScript"
:style="customStyle"
:autodetect="false"
:code="content"
></highlightjs>
</template>
<script lang="ts" setup>
import { CSSProperties } from 'vue';
const editorRef = ref();
const scrollerElement = ref<HTMLElement | null>(null);
const props = defineProps({
modelValue: {
type: String,
default: '',
},
heightDiff: {
type: Number,
default: 280,
},
});
const content = ref('');
const customStyle = computed<CSSProperties>(() => ({
width: '100%',
overflow: 'auto',
}));
const initLog = async () => {
await nextTick();
if (editorRef.value && scrollerElement.value == undefined) {
const parentElement = editorRef.value.$el as HTMLElement;
scrollerElement.value = parentElement.querySelector('.hljs') as HTMLElement;
scrollerElement.value.style['min-height'] = '500px';
scrollerElement.value.style['max-height'] = 'calc(100vh - ' + props.heightDiff + 'px)';
}
};
watch(
() => props.modelValue,
async (newValue) => {
if (editorRef.value && scrollerElement.value != undefined && newValue != content.value) {
content.value = newValue;
scrollerElement.value.scrollTop = scrollerElement.value.scrollHeight;
} else {
initLog();
}
},
{ immediate: true },
);
onMounted(() => {
initLog();
});
</script>

View file

@ -31,7 +31,7 @@
<el-option :value="500" :label="500" /> <el-option :value="500" :label="500" />
<el-option :value="1000" :label="1000" /> <el-option :value="1000" :label="1000" />
</el-select> </el-select>
<div class="margin-button" style="float: left"> <div class="margin-button float-left">
<el-checkbox border @change="searchLogs" v-model="logSearch.isWatch"> <el-checkbox border @change="searchLogs" v-model="logSearch.isWatch">
{{ $t('commons.button.watch') }} {{ $t('commons.button.watch') }}
</el-checkbox> </el-checkbox>
@ -43,14 +43,7 @@
{{ $t('commons.button.clean') }} {{ $t('commons.button.clean') }}
</el-button> </el-button>
</div> </div>
<LogPro v-model="logInfo"></LogPro>
<highlightjs
class="mt-10 editor-main"
ref="editorRef"
language="JavaScript"
:autodetect="false"
:code="logInfo"
></highlightjs>
</template> </template>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
@ -70,6 +63,7 @@ import { ElMessageBox } from 'element-plus';
import { MsgError, MsgSuccess } from '@/utils/message'; import { MsgError, MsgSuccess } from '@/utils/message';
import screenfull from 'screenfull'; import screenfull from 'screenfull';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
import LogPro from '@/components/log-pro/index.vue';
const logVisible = ref(false); const logVisible = ref(false);
const mobile = computed(() => { const mobile = computed(() => {
@ -79,8 +73,6 @@ const mobile = computed(() => {
const logInfo = ref<string>(''); const logInfo = ref<string>('');
const globalStore = GlobalStore(); const globalStore = GlobalStore();
const terminalSocket = ref<WebSocket>(); const terminalSocket = ref<WebSocket>();
const editorRef = ref();
const scrollerElement = ref<HTMLElement | null>(null);
const logSearch = reactive({ const logSearch = reactive({
isWatch: true, isWatch: true,
@ -142,10 +134,6 @@ const searchLogs = async () => {
); );
terminalSocket.value.onmessage = (event) => { terminalSocket.value.onmessage = (event) => {
logInfo.value += event.data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, ''); logInfo.value += event.data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, '');
nextTick(() => {
initLog();
scrollerElement.value.scrollTop = scrollerElement.value.scrollHeight;
});
}; };
}; };
@ -215,13 +203,6 @@ const acceptParams = (props: DialogProps): void => {
onBeforeUnmount(() => { onBeforeUnmount(() => {
handleClose(); handleClose();
}); });
const initLog = () => {
if (editorRef.value && scrollerElement.value == undefined) {
scrollerElement.value = editorRef.value.$el as HTMLElement;
let hljsDom = scrollerElement.value.querySelector('.hljs') as HTMLElement;
hljsDom.style['min-height'] = '500px';
}
};
defineExpose({ defineExpose({
acceptParams, acceptParams,

View file

@ -9,7 +9,7 @@
type="primary" type="primary"
:disabled="mysqlStatus !== 'Running'" :disabled="mysqlStatus !== 'Running'"
:plain="activeName !== 'status'" :plain="activeName !== 'status'"
@click="activeName = 'status'" @click="changeTab('status')"
> >
{{ $t('database.currentStatus') }} {{ $t('database.currentStatus') }}
</el-button> </el-button>
@ -17,7 +17,7 @@
type="primary" type="primary"
:disabled="mysqlStatus !== 'Running'" :disabled="mysqlStatus !== 'Running'"
:plain="activeName !== 'tuning'" :plain="activeName !== 'tuning'"
@click="activeName = 'tuning'" @click="changeTab('tuning')"
> >
{{ $t('database.performanceTuning') }} {{ $t('database.performanceTuning') }}
</el-button> </el-button>
@ -28,14 +28,14 @@
type="primary" type="primary"
:disabled="mysqlStatus !== 'Running'" :disabled="mysqlStatus !== 'Running'"
:plain="activeName !== 'log'" :plain="activeName !== 'log'"
@click="activeName = 'log'" @click="changeTab('log')"
> >
{{ $t('database.log') }} {{ $t('database.log') }}
</el-button> </el-button>
<el-button <el-button
type="primary" type="primary"
:disabled="mysqlStatus !== 'Running'" :disabled="mysqlStatus !== 'Running'"
@click="jumpToSlowlog" @click="changeTab('slowLog')"
:plain="activeName !== 'slowLog'" :plain="activeName !== 'slowLog'"
> >
{{ $t('database.slowLog') }} {{ $t('database.slowLog') }}
@ -48,19 +48,7 @@
<template #main> <template #main>
<div v-if="activeName === 'conf'"> <div v-if="activeName === 'conf'">
<codemirror <CodemirrorPro v-model="mysqlConf" :heightDiff="400"></CodemirrorPro>
:autofocus="true"
:placeholder="$t('commons.msg.noneData')"
:indent-with-tab="true"
:tabSize="4"
:style="{ height: `calc(100vh - ${loadHeight()})`, 'margin-top': '10px' }"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
v-model="mysqlConf"
/>
<el-button class="mt-2.5" @click="getDefaultConfig()"> <el-button class="mt-2.5" @click="getDefaultConfig()">
{{ $t('app.defaultConfig') }} {{ $t('app.defaultConfig') }}
</el-button> </el-button>
@ -79,9 +67,9 @@
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
<Status v-show="activeName === 'status'" ref="statusRef" /> <Status v-if="activeName === 'status'" ref="statusRef" />
<Variables @loading="changeLoading" v-show="activeName === 'tuning'" ref="variablesRef" /> <Variables @loading="changeLoading" v-if="activeName === 'tuning'" ref="variablesRef" />
<div v-show="activeName === 'port'"> <div v-if="activeName === 'port'">
<el-form :model="baseInfo" ref="panelFormRef" label-position="top"> <el-form :model="baseInfo" ref="panelFormRef" label-position="top">
<el-row> <el-row>
<el-col :span="1"><br /></el-col> <el-col :span="1"><br /></el-col>
@ -98,11 +86,11 @@
</el-row> </el-row>
</el-form> </el-form>
</div> </div>
<ContainerLog v-show="activeName === 'log'" ref="dialogContainerLogRef" /> <ContainerLog v-if="activeName === 'log'" ref="dialogContainerLogRef" />
<SlowLog <SlowLog
@loading="changeLoading" @loading="changeLoading"
@refresh="loadBaseInfo" @refresh="loadBaseInfo"
v-show="activeName === 'slowLog'" v-if="activeName === 'slowLog'"
ref="slowLogRef" ref="slowLogRef"
/> />
</template> </template>
@ -140,21 +128,16 @@ import Variables from '@/views/database/mysql/setting/variables/index.vue';
import SlowLog from '@/views/database/mysql/setting/slow-log/index.vue'; import SlowLog from '@/views/database/mysql/setting/slow-log/index.vue';
import ConfirmDialog from '@/components/confirm-dialog/index.vue'; import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { loadDBFile, loadDBBaseInfo, loadMysqlVariables, updateDBFile } from '@/api/modules/database'; import { loadDBFile, loadDBBaseInfo, loadMysqlVariables, updateDBFile } from '@/api/modules/database';
import { ChangePort, CheckAppInstalled, GetAppDefaultConfig } from '@/api/modules/app'; import { ChangePort, CheckAppInstalled, GetAppDefaultConfig } from '@/api/modules/app';
import { Rules } from '@/global/form-rules'; import { Rules } from '@/global/form-rules';
import i18n from '@/lang'; import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import router from '@/routers'; import router from '@/routers';
import { GlobalStore } from '@/store'; import CodemirrorPro from '@/components/codemirror-pro/index.vue';
const globalStore = GlobalStore();
const loading = ref(false); const loading = ref(false);
const extensions = [javascript(), oneDark];
const activeName = ref('conf'); const activeName = ref('conf');
const baseInfo = reactive({ const baseInfo = reactive({
@ -194,13 +177,29 @@ const jumpToConf = async () => {
loadMysqlConf(); loadMysqlConf();
}; };
const loadHeight = () => { const changeTab = (tab: string) => {
return globalStore.openMenuTabs ? '405px' : '375px'; activeName.value = tab;
};
const jumpToSlowlog = async () => { switch (tab) {
activeName.value = 'slowLog'; case 'log':
loadSlowLogs(); nextTick(() => {
loadContainerLog(baseInfo.containerID);
});
break;
case 'slowLog':
nextTick(() => {
loadSlowLogs();
});
break;
case 'status':
nextTick(() => {
statusRef.value!.acceptParams({ type: props.type, database: props.database });
});
break;
case 'tuning':
loadVariables();
break;
}
}; };
const onSubmitChangePort = async () => { const onSubmitChangePort = async () => {
@ -292,7 +291,6 @@ const loadBaseInfo = async () => {
baseInfo.port = res.data?.port; baseInfo.port = res.data?.port;
baseInfo.containerID = res.data?.containerName; baseInfo.containerID = res.data?.containerName;
loadMysqlConf(); loadMysqlConf();
loadContainerLog(baseInfo.containerID);
}; };
const changeLoading = (status: boolean) => { const changeLoading = (status: boolean) => {
@ -345,11 +343,6 @@ const onLoadInfo = async () => {
mysqlStatus.value = res.data.status; mysqlStatus.value = res.data.status;
mysqlVersion.value = res.data.version; mysqlVersion.value = res.data.version;
loadBaseInfo(); loadBaseInfo();
if (mysqlStatus.value === 'Running') {
loadVariables();
loadSlowLogs();
statusRef.value!.acceptParams({ type: props.type, database: props.database });
}
}); });
}; };

View file

@ -10,61 +10,37 @@
/> />
</el-form-item> </el-form-item>
<el-form-item :label="$t('database.longQueryTime')" v-if="detailShow"> <el-form-item :label="$t('database.longQueryTime')" v-if="detailShow">
<div style="float: left"> <div class="float-left">
<el-input type="number" v-model.number="variables.long_query_time" /> <el-input type="number" v-model.number="variables.long_query_time" />
</div> </div>
<el-button style="float: left; margin-left: 10px" @click="changeSlowLogs"> <el-button class="float-left ml-5" @click="changeSlowLogs">
{{ $t('commons.button.save') }} {{ $t('commons.button.save') }}
</el-button> </el-button>
<div style="float: left; margin-left: 20px"> <div class="float-left ml-10">
<el-checkbox style="margin-top: 2px" :disabled="!currentStatus" border v-model="isWatch"> <el-checkbox :disabled="!currentStatus" border v-model="isWatch">
{{ $t('commons.button.watch') }} {{ $t('commons.button.watch') }}
</el-checkbox> </el-checkbox>
</div> </div>
<el-button :disabled="!currentStatus" style="margin-left: 20px" @click="onDownload" icon="Download"> <el-button :disabled="!currentStatus" class="ml-20" @click="onDownload" icon="Download">
{{ $t('file.download') }} {{ $t('file.download') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<codemirror <LogPro v-model="slowLogs"></LogPro>
:autofocus="true"
:placeholder="$t('database.noData')"
:indent-with-tab="true"
:tabSize="4"
:style="{ height: getDynamicHeight(), width: '100%' }"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
@ready="handleReady"
v-model="slowLogs"
:disabled="true"
/>
<ConfirmDialog @cancel="onCancel" ref="confirmDialogRef" @confirm="onSave"></ConfirmDialog> <ConfirmDialog @cancel="onCancel" ref="confirmDialogRef" @confirm="onSave"></ConfirmDialog>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { Codemirror } from 'vue-codemirror'; import { onBeforeUnmount, reactive, ref } from 'vue';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
import { Database } from '@/api/interface/database'; import { Database } from '@/api/interface/database';
import ConfirmDialog from '@/components/confirm-dialog/index.vue'; import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { loadDBFile, updateMysqlVariables } from '@/api/modules/database'; import { loadDBFile, updateMysqlVariables } from '@/api/modules/database';
import { dateFormatForName, downloadWithContent } from '@/utils/util'; import { dateFormatForName, downloadWithContent } from '@/utils/util';
import i18n from '@/lang'; import i18n from '@/lang';
import { MsgError, MsgInfo, MsgSuccess } from '@/utils/message'; import { MsgError, MsgInfo, MsgSuccess } from '@/utils/message';
import { GlobalStore } from '@/store'; import LogPro from '@/components/log-pro/index.vue';
const globalStore = GlobalStore();
const extensions = [javascript(), oneDark];
const slowLogs = ref(); const slowLogs = ref();
const view = shallowRef();
const handleReady = (payload) => {
view.value = payload.view;
};
const detailShow = ref(); const detailShow = ref();
const currentStatus = ref(); const currentStatus = ref();
@ -121,20 +97,20 @@ const handleSlowLogs = async () => {
confirmDialogRef.value!.acceptParams(params); confirmDialogRef.value!.acceptParams(params);
}; };
const getDynamicHeight = () => { // const getDynamicHeight = () => {
if (variables.slow_query_log === 'ON') { // if (variables.slow_query_log === 'ON') {
if (globalStore.openMenuTabs) { // if (globalStore.openMenuTabs) {
return `calc(100vh - 467px)`; // return `calc(100vh - 467px)`;
} else { // } else {
return `calc(100vh - 437px)`; // return `calc(100vh - 437px)`;
} // }
} // }
if (globalStore.openMenuTabs) { // if (globalStore.openMenuTabs) {
return `calc(100vh - 413px)`; // return `calc(100vh - 413px)`;
} else { // } else {
return `calc(100vh - 383px)`; // return `calc(100vh - 383px)`;
} // }
}; // };
const changeSlowLogs = () => { const changeSlowLogs = () => {
if (!(variables.long_query_time > 0 && variables.long_query_time <= 600)) { if (!(variables.long_query_time > 0 && variables.long_query_time <= 600)) {
@ -190,13 +166,13 @@ const onDownload = async () => {
const loadMysqlSlowlogs = async () => { const loadMysqlSlowlogs = async () => {
const res = await loadDBFile(currentDB.type + '-slow-logs', currentDB.database); const res = await loadDBFile(currentDB.type + '-slow-logs', currentDB.database);
slowLogs.value = res.data || ''; slowLogs.value = res.data || '';
nextTick(() => { // nextTick(() => {
const state = view.value.state; // const state = view.value.state;
view.value.dispatch({ // view.value.dispatch({
selection: { anchor: state.doc.length, head: state.doc.length }, // selection: { anchor: state.doc.length, head: state.doc.length },
scrollIntoView: true, // scrollIntoView: true,
}); // });
}); // });
}; };
onBeforeUnmount(() => { onBeforeUnmount(() => {

View file

@ -52,7 +52,7 @@
<LayoutContent> <LayoutContent>
<template #main> <template #main>
<MainDiv :heightDiff="300"> <MainDiv :heightDiff="3200">
<el-radio-group v-model="confShowType" @change="changeMode"> <el-radio-group v-model="confShowType" @change="changeMode">
<el-radio-button value="base">{{ $t('database.baseConf') }}</el-radio-button> <el-radio-button value="base">{{ $t('database.baseConf') }}</el-radio-button>
<el-radio-button value="all">{{ $t('database.allConf') }}</el-radio-button> <el-radio-button value="all">{{ $t('database.allConf') }}</el-radio-button>
@ -125,19 +125,12 @@
</el-row> </el-row>
<div v-if="confShowType === 'all'"> <div v-if="confShowType === 'all'">
<codemirror <CodemirrorPro
:autofocus="true" :heightDiff="400"
placeholder="# The SSH configuration file does not exist or is empty (/etc/ssh/sshd_config)" class="mt-5"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; height: calc(100vh - 405px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
v-model="sshConf" v-model="sshConf"
/> placeholder="# The SSH configuration file does not exist or is empty (/etc/ssh/sshd_config)"
></CodemirrorPro>
<el-button :disabled="loading" type="primary" @click="onSaveFile" style="margin-top: 5px"> <el-button :disabled="loading" type="primary" @click="onSaveFile" style="margin-top: 5px">
{{ $t('commons.button.save') }} {{ $t('commons.button.save') }}
</el-button> </el-button>
@ -155,10 +148,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror';
import FireRouter from '@/views/host/ssh/index.vue'; import FireRouter from '@/views/host/ssh/index.vue';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import PubKey from '@/views/host/ssh/ssh/pubkey/index.vue'; import PubKey from '@/views/host/ssh/ssh/pubkey/index.vue';
import Root from '@/views/host/ssh/ssh/root/index.vue'; import Root from '@/views/host/ssh/ssh/root/index.vue';
import Port from '@/views/host/ssh/ssh/port/index.vue'; import Port from '@/views/host/ssh/ssh/port/index.vue';
@ -168,10 +158,10 @@ import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import { getSSHConf, getSSHInfo, operateSSH, updateSSH, updateSSHByfile } from '@/api/modules/host'; import { getSSHConf, getSSHInfo, operateSSH, updateSSH, updateSSHByfile } from '@/api/modules/host';
import { ElMessageBox, FormInstance } from 'element-plus'; import { ElMessageBox, FormInstance } from 'element-plus';
import CodemirrorPro from '@/components/codemirror-pro/index.vue';
const loading = ref(false); const loading = ref(false);
const formRef = ref(); const formRef = ref();
const extensions = [javascript(), oneDark];
const confShowType = ref('base'); const confShowType = ref('base');
const pubKeyRef = ref(); const pubKeyRef = ref();
const portRef = ref(); const portRef = ref();

View file

@ -143,22 +143,7 @@
<el-option :value="500" :label="500" /> <el-option :value="500" :label="500" />
<el-option :value="1000" :label="1000" /> <el-option :value="1000" :label="1000" />
</el-select> </el-select>
<codemirror <LogPro v-model="logContent"></LogPro>
ref="mymirror"
:autofocus="true"
:placeholder="$t('cronjob.noLogs')"
:indent-with-tab="true"
:tabSize="4"
style="height: calc(100vh - 498px); width: 100%; margin-top: 5px"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
@ready="handleReady"
v-model="logContent"
:disabled="true"
/>
</el-row> </el-row>
</el-form> </el-form>
</el-col> </el-col>
@ -181,9 +166,6 @@
import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue'; import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
import i18n from '@/lang'; import i18n from '@/lang';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import { shortcuts } from '@/utils/shortcuts'; import { shortcuts } from '@/utils/shortcuts';
import { Toolbox } from '@/api/interface/toolbox'; import { Toolbox } from '@/api/interface/toolbox';
@ -197,13 +179,6 @@ const hasRecords = ref();
let timer: NodeJS.Timer | null = null; let timer: NodeJS.Timer | null = null;
const mymirror = ref();
const extensions = [javascript(), oneDark];
const view = shallowRef();
const handleReady = (payload) => {
view.value = payload.view;
};
const recordShow = ref(false); const recordShow = ref(false);
interface DialogProps { interface DialogProps {
rowData: Toolbox.ClamInfo; rowData: Toolbox.ClamInfo;
@ -318,13 +293,6 @@ const loadRecordLog = async () => {
return; return;
} }
logContent.value = res.data; logContent.value = res.data;
nextTick(() => {
const state = view.value.state;
view.value.dispatch({
selection: { anchor: state.doc.length, head: state.doc.length },
scrollIntoView: true,
});
});
}; };
const onClean = async () => { const onClean = async () => {

View file

@ -38,22 +38,14 @@
<el-option :value="500" :label="500" /> <el-option :value="500" :label="500" />
<el-option :value="1000" :label="1000" /> <el-option :value="1000" :label="1000" />
</el-select> </el-select>
<codemirror <CodemirrorPro
:autofocus="true" :heightDiff="400"
:placeholder="$t('commons.msg.noneData')" class="mt-5"
:indent-with-tab="true"
:tabSize="4"
:style="{ height: `calc(100vh - ${loadHeight()})`, 'margin-top': '10px' }"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
@ready="handleReady"
:extensions="extensions"
v-model="content" v-model="content"
:disabled="!canUpdate()" :disabled="!canUpdate()"
/> :placeholder="$t('commons.msg.noneData')"
<el-button type="primary" style="margin-top: 10px" v-if="canUpdate()" @click="onSave"> ></CodemirrorPro>
<el-button type="primary" class="mt-5" v-if="canUpdate()" @click="onSave">
{{ $t('commons.button.save') }} {{ $t('commons.button.save') }}
</el-button> </el-button>
</div> </div>
@ -66,36 +58,19 @@
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted, ref, shallowRef } from 'vue'; import { nextTick, onMounted, ref, shallowRef } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import ClamStatus from '@/views/toolbox/clam/status/index.vue'; import ClamStatus from '@/views/toolbox/clam/status/index.vue';
import { searchClamFile, updateClamFile } from '@/api/modules/toolbox'; import { searchClamFile, updateClamFile } from '@/api/modules/toolbox';
import { oneDark } from '@codemirror/theme-one-dark'; import CodemirrorPro from '@/components/codemirror-pro/index.vue';
import { GlobalStore } from '@/store';
import i18n from '@/lang'; import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
const globalStore = GlobalStore();
const loading = ref(false); const loading = ref(false);
const extensions = [javascript(), oneDark];
const view = shallowRef();
const handleReady = (payload) => {
view.value = payload.view;
};
const activeName = ref('clamd'); const activeName = ref('clamd');
const tail = ref(200); const tail = ref(200);
const content = ref(); const content = ref();
const confirmRef = ref(); const confirmRef = ref();
const loadHeight = () => {
let height = globalStore.openMenuTabs ? '405px' : '375px';
if (!canUpdate()) {
height = globalStore.openMenuTabs ? '383px' : '353px';
}
return height;
};
const canUpdate = () => { const canUpdate = () => {
return activeName.value.indexOf('-log') === -1; return activeName.value.indexOf('-log') === -1;
}; };
@ -110,13 +85,6 @@ const search = async (itemName?: string) => {
.then((res) => { .then((res) => {
loading.value = false; loading.value = false;
content.value = res.data; content.value = res.data;
nextTick(() => {
const state = view.value.state;
view.value.dispatch({
selection: { anchor: state.doc.length, head: state.doc.length },
scrollIntoView: true,
});
});
}) })
.catch(() => { .catch(() => {
loading.value = false; loading.value = false;

View file

@ -1,28 +1,12 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<codemirror <LogPro v-model="content" :heightDiff="320"></LogPro>
:autofocus="true"
:placeholder="$t('commons.msg.noneData')"
:indent-with-tab="true"
:tabSize="4"
style="height: calc(100vh - 375px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
v-model="content"
/>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { GetSupervisorLog } from '@/api/modules/host-tool'; import { GetSupervisorLog } from '@/api/modules/host-tool';
import { javascript } from '@codemirror/lang-javascript'; import LogPro from '@/components/log-pro/index.vue';
import { oneDark } from '@codemirror/theme-one-dark';
const extensions = [javascript(), oneDark];
let content = ref(''); let content = ref('');
let loading = ref(false); let loading = ref(false);