feat(1.5.0)-beta1): 完成日志接入ws
This commit is contained in:
parent
447cd61215
commit
2408463d7c
2
.env
2
.env
@ -6,7 +6,7 @@ VITE_APP_TITLE=Snail Job
|
|||||||
|
|
||||||
VITE_APP_DESC=A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling.
|
VITE_APP_DESC=A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling.
|
||||||
|
|
||||||
VITE_APP_VERSION=1.4.0
|
VITE_APP_VERSION=1.5.0-beta1
|
||||||
|
|
||||||
VITE_APP_DEFAULT_TOKEN=SJ_Wyz3dmsdbDOkDujOTSSoBjGQP1BMsVnj
|
VITE_APP_DEFAULT_TOKEN=SJ_Wyz3dmsdbDOkDujOTSSoBjGQP1BMsVnj
|
||||||
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import {
|
import {
|
||||||
NButton,
|
|
||||||
NCard,
|
NCard,
|
||||||
NCollapse,
|
NCollapse,
|
||||||
NCollapseItem,
|
NCollapseItem,
|
||||||
NDivider,
|
NDivider,
|
||||||
NDropdown,
|
|
||||||
NEmpty,
|
NEmpty,
|
||||||
NScrollbar,
|
NScrollbar,
|
||||||
NSpin,
|
NSpin,
|
||||||
@ -42,14 +40,11 @@ const visible = defineModel<boolean>('show', {
|
|||||||
default: false
|
default: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const isAutoScroll = ref(false);
|
|
||||||
const isFullscreen = ref(true);
|
const isFullscreen = ref(true);
|
||||||
const expandedNames = ref<string[]>([]);
|
const expandedNames = ref<string[]>([]);
|
||||||
const virtualListInst = ref<VirtualListInst>();
|
const virtualListInst = ref<VirtualListInst>();
|
||||||
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>();
|
||||||
const controller = new AbortController();
|
|
||||||
const finished = ref<boolean>(true);
|
const finished = ref<boolean>(true);
|
||||||
|
|
||||||
const pauseLog = () => {
|
const pauseLog = () => {
|
||||||
@ -59,13 +54,18 @@ const pauseLog = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const stopLog = () => {
|
const stopLog = () => {
|
||||||
if (!finished.value) controller.abort();
|
|
||||||
pauseLog();
|
pauseLog();
|
||||||
logList.value = [];
|
logList.value = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getLogList() {
|
async function getLogList() {
|
||||||
|
if (terminalSocket.value) {
|
||||||
|
terminalSocket.value.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (props.type === 'job') {
|
if (props.type === 'job') {
|
||||||
|
const newSocket = initWebSocket('JOB_LOG_SCENE');
|
||||||
|
terminalSocket.value = newSocket ?? undefined;
|
||||||
terminalSocket!.value!.onopen = () => {
|
terminalSocket!.value!.onopen = () => {
|
||||||
const taskData = props.taskData! as Api.Job.JobTask;
|
const taskData = props.taskData! as Api.Job.JobTask;
|
||||||
const msg = {
|
const msg = {
|
||||||
@ -86,74 +86,9 @@ async function getLogList() {
|
|||||||
virtualListInst.value?.scrollTo({ position: 'bottom', debounce: false });
|
virtualListInst.value?.scrollTo({ position: 'bottom', debounce: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// logList.value
|
|
||||||
// .sort((a, b) => Number.parseInt(a.time_stamp, 10) - Number.parseInt(b.time_stamp, 10))
|
|
||||||
// .forEach((item, index) => (item.index = index));
|
|
||||||
// logData.value.push(`${event.data}\n`);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// if (props.type === 'retry') {
|
|
||||||
// const taskData = props.taskData! as Api.RetryTask.RetryTask;
|
|
||||||
// const { data, error } = await fetchRetryLogList({
|
|
||||||
// groupName: taskData.groupName,
|
|
||||||
// retryTaskId: taskData.id!,
|
|
||||||
// startId,
|
|
||||||
// fromIndex,
|
|
||||||
// size: 50
|
|
||||||
// });
|
|
||||||
// logData = data;
|
|
||||||
// logError = error;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!logError && logData) {
|
|
||||||
// // 这里需要判断是否完成
|
|
||||||
// finished.value = syncTime.value === 0;
|
|
||||||
// logList.value.push(logData);
|
|
||||||
// logList.value
|
|
||||||
// .sort((a, b) => Number.parseInt(a.time_stamp, 10) - Number.parseInt(b.time_stamp, 10))
|
|
||||||
// .forEach((item, index) => (item.index = index));
|
|
||||||
// nextTick(() => {
|
|
||||||
// if (isAutoScroll.value) virtualListInst.value?.scrollTo({ position: 'bottom', debounce: true });
|
|
||||||
// });
|
|
||||||
// if (!finished.value && syncTime.value !== 0) {
|
|
||||||
// interval.value = setTimeout(getLogList, syncTime.value * 1000);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (finished.value && syncTime.value !== 0) {
|
|
||||||
// setTimeout(() => {
|
|
||||||
// watchFinished();
|
|
||||||
// }, 5 * 1000);
|
|
||||||
// }
|
|
||||||
// } else if (logError?.code !== 'ERR_CANCELED') {
|
|
||||||
// stopLog();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// async function watchFinished() {
|
|
||||||
// clearTimeout(interval.value);
|
|
||||||
// if (props.type === 'job' && syncTime.value !== 0) {
|
|
||||||
// const taskData = props.taskData! as Api.Job.JobTask;
|
|
||||||
// const { data, error } = await fetchJobLogList(
|
|
||||||
// {
|
|
||||||
// taskBatchId: taskData.taskBatchId,
|
|
||||||
// jobId: taskData.jobId,
|
|
||||||
// taskId: taskData.id,
|
|
||||||
// startId,
|
|
||||||
// fromIndex,
|
|
||||||
// size: 50
|
|
||||||
// },
|
|
||||||
// controller
|
|
||||||
// );
|
|
||||||
// if (!error && data) {
|
|
||||||
// if (data.finished) {
|
|
||||||
// interval.value = setTimeout(watchFinished, 5 * 1000);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// await getLogList();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
stopLog();
|
stopLog();
|
||||||
});
|
});
|
||||||
@ -164,11 +99,6 @@ watch(
|
|||||||
if (val) {
|
if (val) {
|
||||||
if (props.modelValue) {
|
if (props.modelValue) {
|
||||||
logList.value = [...props.modelValue];
|
logList.value = [...props.modelValue];
|
||||||
if (terminalSocket.value) {
|
|
||||||
terminalSocket.value.close();
|
|
||||||
}
|
|
||||||
const newSocket = initWebSocket('JOB_LOG_SCENE');
|
|
||||||
terminalSocket.value = newSocket ?? undefined;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
terminalSocket?.value?.close();
|
terminalSocket?.value?.close();
|
||||||
@ -176,7 +106,6 @@ watch(
|
|||||||
|
|
||||||
if ((val || !props.drawer) && props.type && props.taskData) {
|
if ((val || !props.drawer) && props.type && props.taskData) {
|
||||||
finished.value = false;
|
finished.value = false;
|
||||||
// controller = new AbortController();
|
|
||||||
await getLogList();
|
await getLogList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,57 +152,6 @@ function openNewTab() {
|
|||||||
window.open(url.href);
|
window.open(url.href);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSyncSelect = async (time: number) => {
|
|
||||||
if (time === -1) {
|
|
||||||
if (finished.value) {
|
|
||||||
finished.value = false;
|
|
||||||
await getLogList();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
syncTime.value = time;
|
|
||||||
|
|
||||||
if (time === 0) {
|
|
||||||
pauseLog();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
finished.value = false;
|
|
||||||
await getLogList();
|
|
||||||
};
|
|
||||||
|
|
||||||
const syncOptions = ref([
|
|
||||||
{
|
|
||||||
label: 'Off',
|
|
||||||
key: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Auto(1s)',
|
|
||||||
key: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '5s',
|
|
||||||
key: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '10s',
|
|
||||||
key: 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '30s',
|
|
||||||
key: 30
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '1m',
|
|
||||||
key: 60
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '5m',
|
|
||||||
key: 300
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
const SnailLogComponent = defineComponent({
|
const SnailLogComponent = defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
if (finished.value && logList.value.length === 0) {
|
if (finished.value && logList.value.length === 0) {
|
||||||
@ -336,7 +214,6 @@ const SnailLogComponent = defineComponent({
|
|||||||
ref={virtualListInst}
|
ref={virtualListInst}
|
||||||
class="virtual-list"
|
class="virtual-list"
|
||||||
itemSize={85}
|
itemSize={85}
|
||||||
itemResizable
|
|
||||||
paddingBottom={16}
|
paddingBottom={16}
|
||||||
items={logList.value}
|
items={logList.value}
|
||||||
scrollbarProps={{ xScrollable: true }}
|
scrollbarProps={{ xScrollable: true }}
|
||||||
@ -397,32 +274,8 @@ const SnailLogComponent = defineComponent({
|
|||||||
日志正在加载
|
日志正在加载
|
||||||
</NTooltip>
|
</NTooltip>
|
||||||
<span class="ml-6px">{{ title }}</span>
|
<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>
|
||||||
<div class="flex-center">
|
<div class="flex-center">
|
||||||
<ButtonIcon
|
|
||||||
size="tiny"
|
|
||||||
:tooltip-content="isAutoScroll ? '关闭自动滚动' : '开启自动滚动'"
|
|
||||||
@click="() => (isAutoScroll = !isAutoScroll)"
|
|
||||||
>
|
|
||||||
<icon-streamline:synchronize-disable v-if="isAutoScroll" />
|
|
||||||
<icon-streamline:interface-arrows-vertical-scroll-point-move-scroll-vertical v-else />
|
|
||||||
</ButtonIcon>
|
|
||||||
<ButtonIcon
|
<ButtonIcon
|
||||||
size="tiny"
|
size="tiny"
|
||||||
icon="hugeicons:share-01"
|
icon="hugeicons:share-01"
|
||||||
@ -451,31 +304,6 @@ 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">
|
||||||
<NDropdown trigger="hover" :options="syncOptions" width="trigger" @select="handleSyncSelect">
|
|
||||||
<NTooltip placement="right">
|
|
||||||
<template #trigger>
|
|
||||||
<NButton dashed class="mx-12px 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>
|
|
||||||
<ButtonIcon
|
|
||||||
size="tiny"
|
|
||||||
class="mr-12px"
|
|
||||||
:tooltip-content="isAutoScroll ? '关闭自动滚动' : '开启自动滚动'"
|
|
||||||
@click="() => (isAutoScroll = !isAutoScroll)"
|
|
||||||
>
|
|
||||||
<icon-streamline:synchronize-disable v-if="isAutoScroll" />
|
|
||||||
<icon-streamline:interface-arrows-vertical-scroll-point-move-scroll-vertical v-else />
|
|
||||||
</ButtonIcon>
|
|
||||||
<NTooltip v-if="finished">
|
<NTooltip v-if="finished">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<icon-material-symbols:check-circle class="text-20px color-success" />
|
<icon-material-symbols:check-circle class="text-20px color-success" />
|
||||||
|
@ -42,7 +42,7 @@ const title = computed(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<LogDrawer :drawer="false" :title="title" :type="type" :task-data="taskData" />
|
<LogDrawerWs :drawer="false" :title="title" :type="type" :task-data="taskData" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user