feat(sj_map_reduce): 工作流批次详情新增实时刷新功能

This commit is contained in:
xlsea 2024-07-03 14:43:38 +08:00
parent 8599258b1d
commit 0b78b17600
5 changed files with 137 additions and 18 deletions

View File

@ -32,21 +32,19 @@ const visible = defineModel<boolean>('show', {
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>();
const controller = new AbortController(); let controller = new AbortController();
const finished = ref<boolean>(true); const finished = ref<boolean>(true);
let startId = '0'; let startId = '0';
let fromIndex: number = 0; let fromIndex: number = 0;
let axiosController = new AbortController();
const pauseLog = () => { const pauseLog = () => {
finished.value = true; finished.value = true;
controller.abort();
clearTimeout(interval.value); clearTimeout(interval.value);
interval.value = undefined; interval.value = undefined;
}; };
const stopLog = () => { const stopLog = () => {
if (!finished.value) axiosController.abort(); if (!finished.value) controller.abort();
pauseLog(); pauseLog();
startId = '0'; startId = '0';
fromIndex = 0; fromIndex = 0;
@ -68,7 +66,7 @@ async function getLogList() {
fromIndex, fromIndex,
size: 50 size: 50
}, },
axiosController controller
); );
logData = data; logData = data;
logError = error; logError = error;
@ -119,7 +117,7 @@ watch(
if ((val || !props.drawer) && props.type && props.taskData) { if ((val || !props.drawer) && props.type && props.taskData) {
finished.value = false; finished.value = false;
axiosController = new AbortController(); controller = new AbortController();
await getLogList(); await getLogList();
} }
@ -265,7 +263,7 @@ const SnailLogComponent = defineComponent({
</script> </script>
<template> <template>
<NDrawer v-if="drawer" v-model:show="visible" width="100%" display-directive="if"> <NDrawer v-if="drawer" v-model:show="visible" width="100%" display-directive="if" :auto-focus="false">
<NDrawerContent closable> <NDrawerContent closable>
<template #header> <template #header>
<div class="flex-center"> <div class="flex-center">
@ -287,10 +285,10 @@ const SnailLogComponent = defineComponent({
</NTooltip> </NTooltip>
<span class="ml-6px">{{ title }}</span> <span class="ml-6px">{{ title }}</span>
<ButtonIcon icon="hugeicons:share-01" tooltip-content="在新标签页打开" class="ml-6px" @click="openNewTab" /> <ButtonIcon icon="hugeicons:share-01" tooltip-content="在新标签页打开" class="ml-6px" @click="openNewTab" />
<NDropdown trigger="hover" :options="syncOptions" @select="handleSyncSelect"> <NDropdown trigger="hover" :options="syncOptions" width="trigger" @select="handleSyncSelect">
<NTooltip placement="right"> <NTooltip placement="right">
<template #trigger> <template #trigger>
<NButton quaternary class="ml-3px w-136px" @click="handleSyncSelect(-1)"> <NButton dashed class="ml-3px 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" />
@ -311,10 +309,10 @@ 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" @select="handleSyncSelect"> <NDropdown trigger="hover" :options="syncOptions" width="trigger" @select="handleSyncSelect">
<NTooltip placement="right"> <NTooltip placement="right">
<template #trigger> <template #trigger>
<NButton quaternary class="ml-3px w-136px" @click="handleSyncSelect(-1)"> <NButton dashed class="ml-3px 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" />

View File

@ -236,7 +236,7 @@ const onUpdatePage = (page: number) => {
</NSpin> </NSpin>
<slot></slot> <slot></slot>
</NTabPane> </NTabPane>
<NTabPane name="task"> <NTabPane name="task" :disabled="jobData.taskBatchStatus === 99">
<template #tab> <template #tab>
<span>任务项列表</span> <span>任务项列表</span>
</template> </template>
@ -271,7 +271,7 @@ const onUpdatePage = (page: number) => {
重试 重试
</NButton> </NButton>
</template> </template>
<JobTaskListTable class="mt-16px" :row-data="jobData as Api.JobBatch.JobBatch" @show-log="getLogRows" /> <JobTaskListTable class="mt-16px" :row-data="jobData as any" @show-log="getLogRows" />
</NCard> </NCard>
</NTabPane> </NTabPane>
</NTabs> </NTabs>

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, watch } from 'vue'; import { onMounted, ref, useSlots, watch } from 'vue';
import VueDragResize from 'vue-drag-resize/src'; import VueDragResize from 'vue-drag-resize/src';
import { $t } from '@/locales'; import { $t } from '@/locales';
import NodeWrap from './modules/nodes/node-wrap.vue'; import NodeWrap from './modules/nodes/node-wrap.vue';
@ -29,6 +29,8 @@ interface Emits {
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
const slots = useSlots();
const zoom = ref<number>(100); const zoom = ref<number>(100);
const nodeData = ref<Workflow.NodeDataType>({}); const nodeData = ref<Workflow.NodeDataType>({});
@ -144,6 +146,9 @@ const onDragstop = () => {
<NButton type="info" @click="save">保存</NButton> <NButton type="info" @click="save">保存</NButton>
<NButton class="ml-16px" @click="cancel">取消</NButton> <NButton class="ml-16px" @click="cancel">取消</NButton>
</div> </div>
<div v-if="disabled && slots.buttons" class="buttons">
<slot name="buttons"></slot>
</div>
</div> </div>
</NAffix> </NAffix>
<NSpin :show="spinning"> <NSpin :show="spinning">

View File

@ -20,6 +20,8 @@ declare namespace Workflow {
wfContexts?: { key: string; value: string | number | boolean; type: string }[]; wfContexts?: { key: string; value: string | number | boolean; type: string }[];
/** 工作流状态 */ /** 工作流状态 */
workflowStatus?: Api.Common.WorkFlowNodeStatus; workflowStatus?: Api.Common.WorkFlowNodeStatus;
/** 工作流批次状态 */
workflowBatchStatus?: Api.Common.TaskBatchStatus;
/** 描述 */ /** 描述 */
description?: string; description?: string;
/** 流程配置 */ /** 流程配置 */

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from 'vue'; import { onBeforeUnmount, onMounted, ref } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import Workflow from '@/components/workflow'; import Workflow from '@/components/workflow';
import { useWorkflowStore } from '@/store/modules/workflow'; import { useWorkflowStore } from '@/store/modules/workflow';
@ -9,30 +9,144 @@ const store = useWorkflowStore();
const route = useRoute(); const route = useRoute();
const spinning = ref(false); const spinning = ref(false);
const id: string = String(route.query.id); const id: string = String(route.query.id);
const node = ref<Workflow.NodeDataType>({}); const node = ref<Workflow.NodeDataType>({});
const syncTime = ref(0);
const interval = ref<NodeJS.Timeout>();
const controller = new AbortController();
const finished = ref<boolean>(true);
const pauseBatch = () => {
finished.value = true;
controller.abort();
clearTimeout(interval.value);
interval.value = undefined;
};
const stopBatch = () => {
if (!finished.value) controller.abort();
pauseBatch();
node.value = {};
store.clear();
};
const getBatchDetail = async () => { const getBatchDetail = async () => {
spinning.value = true; spinning.value = true;
const { data, error } = await fetchWorkflowBatchInfo(id); const { data, error } = await fetchWorkflowBatchInfo(id);
if (!error) { if (!error) {
node.value = data; node.value = data;
finished.value = !(data.workflowBatchStatus && [1, 2].includes(data.workflowBatchStatus));
if (!finished.value) {
clearTimeout(interval.value);
interval.value = setTimeout(getBatchDetail, syncTime.value * 1000);
}
} else if (error?.code !== 'ERR_CANCELED') {
stopBatch();
} }
spinning.value = false; spinning.value = false;
}; };
const handleSyncSelect = async (time: number) => {
if (time === -1) {
if (finished.value) {
finished.value = false;
await getBatchDetail();
}
return;
}
if (time === 0) {
pauseBatch();
return;
}
syncTime.value = time;
finished.value = false;
await getBatchDetail();
};
onMounted(() => { onMounted(() => {
store.clear(); store.clear();
store.setType(2); store.setType(2);
store.setId(id); store.setId(id);
getBatchDetail(); getBatchDetail();
}); });
onBeforeUnmount(() => {
stopBatch();
});
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
}
]);
</script> </script>
<template> <template>
<Workflow v-model="node" :spinning="spinning" disabled /> <Workflow v-model="node" :spinning="spinning" disabled>
<template #buttons>
<div class="flex-center">
<NDropdown trigger="hover" width="trigger" :options="syncOptions" @select="handleSyncSelect">
<NTooltip placement="left">
<template #trigger>
<NButton dashed class="mr-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>
<NTooltip v-if="finished" placement="top">
<template #trigger>
<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>
</div>
</template>
</Workflow>
</template> </template>
<style scoped></style> <style scoped></style>