feat(sj_map_reduce): 日志组件新增自动滚动和缩放功能
This commit is contained in:
parent
84700f1872
commit
47341ad6d7
@ -1,6 +1,17 @@
|
|||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { NButton, NCard, NCollapse, NCollapseItem, NDivider, NDropdown, NEmpty, NSpin, NVirtualList } from 'naive-ui';
|
import {
|
||||||
import { defineComponent, onBeforeUnmount, ref, watch } from 'vue';
|
NButton,
|
||||||
|
NCard,
|
||||||
|
NCollapse,
|
||||||
|
NCollapseItem,
|
||||||
|
NDivider,
|
||||||
|
NDropdown,
|
||||||
|
NEmpty,
|
||||||
|
NSpin,
|
||||||
|
NVirtualList,
|
||||||
|
type VirtualListInst
|
||||||
|
} from 'naive-ui';
|
||||||
|
import { defineComponent, nextTick, onBeforeUnmount, ref, watch } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { fetchJobLogList, fetchRetryLogList } from '@/service/api/log';
|
import { fetchJobLogList, fetchRetryLogList } from '@/service/api/log';
|
||||||
import ButtonIcon from '@/components/custom/button-icon.vue';
|
import ButtonIcon from '@/components/custom/button-icon.vue';
|
||||||
@ -29,6 +40,9 @@ const visible = defineModel<boolean>('show', {
|
|||||||
default: false
|
default: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isAutoScroll = ref(true);
|
||||||
|
const isFullscreen = ref(true);
|
||||||
|
const virtualListInst = ref<VirtualListInst>();
|
||||||
const syncTime = ref(1);
|
const syncTime = ref(1);
|
||||||
const logList = ref<Api.JobLog.JobMessage[]>([]);
|
const logList = ref<Api.JobLog.JobMessage[]>([]);
|
||||||
const interval = ref<NodeJS.Timeout>();
|
const interval = ref<NodeJS.Timeout>();
|
||||||
@ -94,6 +108,9 @@ async function getLogList() {
|
|||||||
logList.value.sort((a, b) => Number.parseInt(a.time_stamp, 10) - Number.parseInt(b.time_stamp, 10));
|
logList.value.sort((a, b) => Number.parseInt(a.time_stamp, 10) - Number.parseInt(b.time_stamp, 10));
|
||||||
}
|
}
|
||||||
if (!finished.value && syncTime.value !== 0) {
|
if (!finished.value && syncTime.value !== 0) {
|
||||||
|
nextTick(() => {
|
||||||
|
if (isAutoScroll.value) virtualListInst.value?.scrollTo({ position: 'bottom' });
|
||||||
|
});
|
||||||
clearTimeout(interval.value);
|
clearTimeout(interval.value);
|
||||||
interval.value = setTimeout(getLogList, syncTime.value * 1000);
|
interval.value = setTimeout(getLogList, syncTime.value * 1000);
|
||||||
}
|
}
|
||||||
@ -241,17 +258,29 @@ const SnailLogComponent = defineComponent({
|
|||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<code class="snail-log">
|
<code class="snail-log">
|
||||||
<NVirtualList class="virtual-list" itemSize={65} items={logList.value}>
|
<NVirtualList
|
||||||
|
ref={virtualListInst}
|
||||||
|
class="virtual-list"
|
||||||
|
itemSize={85}
|
||||||
|
items={logList.value}
|
||||||
|
scrollbar-props={{ xScrollable: true }}
|
||||||
|
>
|
||||||
{{
|
{{
|
||||||
default: ({ item: message }: { item: Api.JobLog.JobMessage }) => (
|
default: ({ item: message }: { item: Api.JobLog.JobMessage }) => (
|
||||||
<pre>
|
<pre key={message.time_stamp} class="h-85px">
|
||||||
<span class="log-hljs-time inline-block">{timestampToDate(message.time_stamp)}</span>
|
<div>
|
||||||
<span class={`log-hljs-level-${message.level} ml-12px mr-12px inline-block`}>{`${message.level}`}</span>
|
<span class="log-hljs-time inline-block">{timestampToDate(message.time_stamp)}</span>
|
||||||
<span class="log-hljs-thread mr-12px inline-block">{`[${message.host}:${message.port}]`}</span>
|
<span
|
||||||
<span class="log-hljs-thread mr-12px inline-block">{`[${message.thread}]`}</span>
|
class={`log-hljs-level-${message.level} ml-12px mr-12px inline-block`}
|
||||||
<span class="log-hljs-location">{`${message.location}: \n`}</span> -
|
>{`${message.level}`}</span>
|
||||||
<span class="pl-6px">{`${message.message}`}</span>
|
<span class="log-hljs-thread mr-12px inline-block">{`[${message.host}:${message.port}]`}</span>
|
||||||
{throwableComponent(message.throwable)}
|
<span class="log-hljs-thread mr-12px inline-block">{`[${message.thread}]`}</span>
|
||||||
|
</div>
|
||||||
|
<div class="log-hljs-location">{`${message.location}: `}</div>
|
||||||
|
<div>
|
||||||
|
<span class="pl-6px">- {`${message.message}`}</span>
|
||||||
|
{throwableComponent(message.throwable)}
|
||||||
|
</div>
|
||||||
<NDivider />
|
<NDivider />
|
||||||
</pre>
|
</pre>
|
||||||
)
|
)
|
||||||
@ -264,44 +293,68 @@ const SnailLogComponent = defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NDrawer v-if="drawer" v-model:show="visible" width="100%" display-directive="if" :auto-focus="false">
|
<NDrawer
|
||||||
|
v-if="drawer"
|
||||||
|
v-model:show="visible"
|
||||||
|
:width="isFullscreen ? '100%' : '50%'"
|
||||||
|
display-directive="if"
|
||||||
|
:auto-focus="false"
|
||||||
|
>
|
||||||
<NDrawerContent closable>
|
<NDrawerContent closable>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex-center">
|
<div class="flex items-center justify-between" :class="`tool-header${isFullscreen ? '-full' : ''}`">
|
||||||
<NTooltip v-if="finished">
|
<div class="flex-center">
|
||||||
<template #trigger>
|
<NTooltip v-if="finished">
|
||||||
<icon-material-symbols:check-circle class="text-20px color-success" />
|
|
||||||
</template>
|
|
||||||
日志加载完成
|
|
||||||
</NTooltip>
|
|
||||||
<NTooltip v-else>
|
|
||||||
<template #trigger>
|
|
||||||
<NSpin size="small">
|
|
||||||
<template #icon>
|
|
||||||
<icon-nonicons:loading-16 />
|
|
||||||
</template>
|
|
||||||
</NSpin>
|
|
||||||
</template>
|
|
||||||
日志正在加载
|
|
||||||
</NTooltip>
|
|
||||||
<span class="ml-6px">{{ title }}</span>
|
|
||||||
<ButtonIcon icon="hugeicons:share-01" tooltip-content="在新标签页打开" class="ml-6px" @click="openNewTab" />
|
|
||||||
<NDropdown trigger="hover" :options="syncOptions" width="trigger" @select="handleSyncSelect">
|
|
||||||
<NTooltip placement="right">
|
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton dashed class="ml-3px w-136px" @click="handleSyncSelect(-1)">
|
<icon-material-symbols:check-circle class="text-20px color-success" />
|
||||||
<template #icon>
|
|
||||||
<div class="flex-center gap-8px">
|
|
||||||
<icon-solar:refresh-outline class="text-18px" />
|
|
||||||
{{ syncOptions.filter(item => item.key === syncTime)[0].label }}
|
|
||||||
<SvgIcon icon="material-symbols:expand-more-rounded" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</NButton>
|
|
||||||
</template>
|
</template>
|
||||||
自动刷新频率
|
日志加载完成
|
||||||
</NTooltip>
|
</NTooltip>
|
||||||
</NDropdown>
|
<NTooltip v-else>
|
||||||
|
<template #trigger>
|
||||||
|
<NSpin size="small">
|
||||||
|
<template #icon>
|
||||||
|
<icon-nonicons:loading-16 />
|
||||||
|
</template>
|
||||||
|
</NSpin>
|
||||||
|
</template>
|
||||||
|
日志正在加载
|
||||||
|
</NTooltip>
|
||||||
|
<span class="ml-6px">{{ title }}</span>
|
||||||
|
<NDropdown trigger="hover" :options="syncOptions" width="trigger" @select="handleSyncSelect">
|
||||||
|
<NTooltip placement="right">
|
||||||
|
<template #trigger>
|
||||||
|
<NButton dashed class="ml-16px w-136px" @click="handleSyncSelect(-1)">
|
||||||
|
<template #icon>
|
||||||
|
<div class="flex-center gap-8px">
|
||||||
|
<icon-solar:refresh-outline class="text-18px" />
|
||||||
|
{{ syncOptions.filter(item => item.key === syncTime)[0].label }}
|
||||||
|
<SvgIcon icon="material-symbols:expand-more-rounded" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</NButton>
|
||||||
|
</template>
|
||||||
|
自动刷新频率
|
||||||
|
</NTooltip>
|
||||||
|
</NDropdown>
|
||||||
|
</div>
|
||||||
|
<div class="flex-center">
|
||||||
|
<NSwitch v-model:value="isAutoScroll" :round="false" size="large">
|
||||||
|
<template #checked>自动滚动</template>
|
||||||
|
<template #unchecked>自动滚动</template>
|
||||||
|
</NSwitch>
|
||||||
|
<ButtonIcon
|
||||||
|
size="tiny"
|
||||||
|
icon="hugeicons:share-01"
|
||||||
|
tooltip-content="在新标签页打开"
|
||||||
|
class="ml-6px"
|
||||||
|
@click="openNewTab"
|
||||||
|
/>
|
||||||
|
<ButtonIcon size="tiny" @click="() => (isFullscreen = !isFullscreen)">
|
||||||
|
<icon-material-symbols:close-fullscreen-rounded v-if="isFullscreen" />
|
||||||
|
<icon-material-symbols:open-in-full-rounded v-else />
|
||||||
|
</ButtonIcon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="logList.length === 0" class="h-full flex-center">
|
<div v-if="logList.length === 0" class="h-full flex-center">
|
||||||
@ -314,10 +367,14 @@ const SnailLogComponent = defineComponent({
|
|||||||
<NCard v-else :bordered="false" :title="title" size="small" class="h-full sm:flex-1-hidden card-wrapper">
|
<NCard v-else :bordered="false" :title="title" size="small" class="h-full sm:flex-1-hidden card-wrapper">
|
||||||
<template #header-extra>
|
<template #header-extra>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
|
<NSwitch v-model:value="isAutoScroll" :round="false" size="large">
|
||||||
|
<template #checked>自动滚动</template>
|
||||||
|
<template #unchecked>自动滚动</template>
|
||||||
|
</NSwitch>
|
||||||
<NDropdown trigger="hover" :options="syncOptions" width="trigger" @select="handleSyncSelect">
|
<NDropdown trigger="hover" :options="syncOptions" width="trigger" @select="handleSyncSelect">
|
||||||
<NTooltip placement="right">
|
<NTooltip placement="right">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton dashed class="ml-3px w-136px" @click="handleSyncSelect(-1)">
|
<NButton dashed class="mx-16px w-136px" @click="handleSyncSelect(-1)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<div class="flex-center gap-8px">
|
<div class="flex-center gap-8px">
|
||||||
<icon-solar:refresh-outline class="text-18px" />
|
<icon-solar:refresh-outline class="text-18px" />
|
||||||
@ -371,7 +428,7 @@ const SnailLogComponent = defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
white-space: pre-wrap;
|
// white-space: pre-wrap;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@ -429,4 +486,12 @@ const SnailLogComponent = defineComponent({
|
|||||||
font-size: 18px !important;
|
font-size: 18px !important;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tool-header-full {
|
||||||
|
width: calc(100vw - 72px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-header {
|
||||||
|
width: calc(50vw - 72px);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -302,7 +302,7 @@ async function handleStopJob(id: string) {
|
|||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="data"
|
:data="data"
|
||||||
:flex-height="!appStore.isMobile"
|
:flex-height="!appStore.isMobile"
|
||||||
:scroll-x="962"
|
:scroll-x="2000"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
remote
|
remote
|
||||||
:row-key="row => row.id"
|
:row-key="row => row.id"
|
||||||
|
Loading…
Reference in New Issue
Block a user