Skip to content

Commit

Permalink
feat(frontend): 任务中的人工确认节点逻辑优化 TencentBlueKing#6179
Browse files Browse the repository at this point in the history
  • Loading branch information
3octaves authored and jinquantianxia committed Sep 4, 2024
1 parent 20ac1f9 commit 95d22a5
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 50 deletions.
4 changes: 4 additions & 0 deletions dbm-ui/frontend/src/locales/zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -3462,5 +3462,9 @@
"% 或 ? 不允许单独使用": "% 或 ? 不允许单独使用",
"不允许为 *": "不允许为 *",
"RedisCluster集群": "RedisCluster 集群",
"任务_待确认": "任务“待确认”",
"任务_执行成功": "任务“执行成功”",
"任务_执行失败": "任务“执行失败”",
"确认继续所有人工确认节点": "确认继续所有人工确认节点",
"这行勿动!新增翻译请在上一行添加!": ""
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ export default class GraphRender {

{flowInfo.status !== 'REVOKED' && node.children === undefined && (
<div class='node-ractangle__operations'>
{status === 'RUNNING' && (
{!todoNodeIdList.includes(node.id) && status === 'RUNNING' && (
<i
class='operation-icon db-icon-qiangzhizhongzhi'
v-bk-tooltips={t('强制失败')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@
(e: 'after-show', value: typeof treeRef): void;
}
interface Exposes {
close: () => void;
getTreeRef: () => typeof treeRef;
isOpen: () => boolean;
}
withDefaults(defineProps<Props>(), {
theme: 'error',
children: 'children',
Expand All @@ -112,6 +118,18 @@
const handleShowFailNodePanel = () => {
isShowNodePanel.value = true;
};
defineExpose<Exposes>({
close() {
isShowNodePanel.value = false;
},
getTreeRef() {
return treeRef;
},
isOpen() {
return isShowNodePanel.value === true;
},
});
</script>

<style lang="less">
Expand Down
140 changes: 104 additions & 36 deletions dbm-ui/frontend/src/views/task-history/pages/Details.vue
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
@click.stop>
<PreviewNodeTree
v-if="todoNodesCount > 0"
ref="todoToolPreviewNodeTreeRef"
children="todoChildren"
margin-right
:nodes-count="todoNodesCount"
Expand All @@ -127,17 +128,18 @@
theme="warning"
title-keypath="人工确认节点(n)"
:tooltips="t('人工确认节点列表')"
@after-show="(treeRef: Ref) => handleNodeTreeAfterShow(treeRef, false)"
@after-show="(treeRef: Ref) => handleToolNodeTreeAfterShow(treeRef, false)"
@node-click="(node: TaskflowList[number], treeRef: Ref) => handleTreeNodeClick(node, treeRef, false)" />
<PreviewNodeTree
v-if="flowState.details.flow_info?.status === 'FAILED'"
ref="failedToolPreviewNodeTreeRef"
children="failedChildren"
:nodes-count="failNodesCount"
:nodes-tree-data="failNodesTreeData"
status-keypath="失败n"
title-keypath="失败节点(n)"
:tooltips="t('失败节点列表')"
@after-show="(treeRef: Ref) => handleNodeTreeAfterShow(treeRef)"
@after-show="(treeRef: Ref) => handleToolNodeTreeAfterShow(treeRef)"
@node-click="(node: TaskflowList[number], treeRef: Ref) => handleTreeNodeClick(node, treeRef)" />
<i
v-bk-tooltips="t('放大')"
Expand Down Expand Up @@ -266,6 +268,7 @@
<span>
<PreviewNodeTree
v-if="flowState.details.flow_info?.status === 'FAILED'"
ref="todoTopPreviewNodeTreeRef"
children="failedChildren"
:nodes-count="failNodesCount"
:nodes-tree-data="failNodesTreeData"
Expand All @@ -276,6 +279,7 @@
@node-click="(node: TaskflowList[number], treeRef: Ref) => handleTreeNodeClick(node, treeRef)" />
<PreviewNodeTree
v-else-if="todoNodesCount > 0"
ref="failedTopPreviewNodeTreeRef"
children="todoChildren"
:nodes-count="todoNodesCount"
:nodes-tree-data="todoNodesTreeData"
Expand Down Expand Up @@ -426,6 +430,10 @@
const todoNodesTreeData = ref<TaskflowList>([]);
const failNodesTreeData = ref<TaskflowList>([]);
const failNodesCount = ref(0);
const todoTopPreviewNodeTreeRef = ref<InstanceType<typeof PreviewNodeTree>>()
const failedTopPreviewNodeTreeRef = ref<InstanceType<typeof PreviewNodeTree>>()
const todoToolPreviewNodeTreeRef = ref<InstanceType<typeof PreviewNodeTree>>()
const failedToolPreviewNodeTreeRef = ref<InstanceType<typeof PreviewNodeTree>>()
// const failNodeTreeRef = ref();
// const topFailNodeTreeRef = ref();
// const isShowFailNodePanel = ref(false);
Expand Down Expand Up @@ -625,12 +633,88 @@
*/
const { isFullscreen, toggle } = useFullscreen(flowTopoRef);

const expandNodes:string[] = [];
const expandFailedNodeObjects: TaskflowList = [];
const expandTodoNodeObjects: TaskflowList = [];
let expandFailedNodeObjects: TaskflowList = [];
let expandTodoNodeObjects: TaskflowList = [];
const expandNodes: string[] = [];
const showResultFileTypes: TicketTypesStrings[] = [TicketTypes.REDIS_KEYS_EXTRACT, TicketTypes.REDIS_KEYS_DELETE];

const generateFailNodesTree = (activities: TaskflowDetails['activities'] ) => {
watch(() => flowState.details, () => {
// if (failNodesTreeData.value.length > 0 || todoNodesTreeData.value.length > 0) {
// return
// };
// failNodesCount.value = 0;

// if (flowState.details.activities) {
// failNodesTreeData.value = flowState.details.flow_info?.status === 'FAILED' ? generateFailNodesTree(flowState.details.activities) : [];

// const todoNodeIdList = flowState.details.todos.map(todoItem => todoItem.context.node_id)
// todoNodesTreeData.value = todoNodeIdList.length ? generateTodoNodesTree(flowState.details.activities, todoNodeIdList) : [];
// }

// 只计算数量,当 待确认节点数 或 失败节点数 变化时,才刷新树结构
if (flowState.details.activities) {
let failNodesNum = 0

const getFailNodesNum = (activities: TaskflowDetails['activities']) => {
const flowList: TaskflowList = []
Object.values(activities).forEach(item => {
if (item.status === 'FAILED') {
if (item.pipeline) {
getFailNodesNum(item.pipeline.activities)
} else {
failNodesNum = failNodesNum + 1;
}
}
})
return flowList;
}
getFailNodesNum(flowState.details.activities)

failNodesCount.value = failNodesNum
}
})

watch(failNodesCount, () => {
isFindFirstLeafFailNode = false;
failLeafNodes.value = []
expandFailedNodeObjects = []
failNodesTreeData.value = flowState.details.flow_info?.status === 'FAILED' ? generateFailNodesTree(flowState.details.activities) : [];

setTreeOpen([
failedTopPreviewNodeTreeRef,
failedToolPreviewNodeTreeRef
])
})

watch(todoNodesCount, () => {
isFindFirstLeafTodoNode = false
expandTodoNodeObjects = []
const todoNodeIdList = flowState.details.todos.map(todoItem => todoItem.context.node_id)
todoNodesTreeData.value = todoNodeIdList.length ? generateTodoNodesTree(flowState.details.activities, todoNodeIdList) : [];

setTreeOpen([
todoTopPreviewNodeTreeRef,
todoToolPreviewNodeTreeRef,
], false)
})

watch(() => baseInfo.value.status, (status) => {
if (status && flowState.instance === null) {
setTimeout(() => {
const todoNodeIdList = flowState.details.todos.map(todoItem => todoItem.context.node_id)
flowState.instance = new GraphCanvas(`#${flowState.flowSelectorId}`, baseInfo.value, todoNodeIdList);
flowState.instance
.on('nodeClick', handleNodeClick)
.on('nodeMouseEnter', handleNodeMouseEnter)
.on('nodeMouseLeave', handleNodeMouseLeave);
retryRenderFailedTips();
});
}
}, {
immediate: true,
});

const generateFailNodesTree = (activities: TaskflowDetails['activities']) => {
const flowList: TaskflowList = []
Object.values(activities).forEach(item => {
if (item.status === 'FAILED') {
Expand All @@ -645,7 +729,7 @@
});
} else {
isFindFirstLeafFailNode = true;
failNodesCount.value = failNodesCount.value + 1;
// failNodesCount.value = failNodesCount.value + 1;
failLeafNodes.value.push({ data: _.cloneDeep(item) } as GraphNode)
}
}
Expand Down Expand Up @@ -678,38 +762,22 @@
return flowList;
}

watch(() => flowState.details, () => {
if (failNodesTreeData.value.length > 0 || todoNodesTreeData.value.length > 0) {
return
};

failNodesCount.value = 0;
if (flowState.details.activities) {
if (flowState.details.flow_info?.status === 'FAILED') {
failNodesTreeData.value = generateFailNodesTree(flowState.details.activities);
const setTreeOpen = (refList: Array<typeof failedTopPreviewNodeTreeRef>, isFailed = true) => {
refList.forEach((refItem) => {
if (refItem.value?.isOpen()) {
handleNodeTreeAfterShow(refItem.value.getTreeRef(), isFailed)
}
const todoNodeIdList = flowState.details.todos.map(todoItem => todoItem.context.node_id)
if (todoNodeIdList.length) {
todoNodesTreeData.value = generateTodoNodesTree(flowState.details.activities, todoNodeIdList);
}
}
})
})
}

watch(() => baseInfo.value.status, (status) => {
if (status && flowState.instance === null) {
setTimeout(() => {
const todoNodeIdList = flowState.details.todos.map(todoItem => todoItem.context.node_id)
flowState.instance = new GraphCanvas(`#${flowState.flowSelectorId}`, baseInfo.value, todoNodeIdList);
flowState.instance
.on('nodeClick', handleNodeClick)
.on('nodeMouseEnter', handleNodeMouseEnter)
.on('nodeMouseLeave', handleNodeMouseLeave);
retryRenderFailedTips();
});
const handleToolNodeTreeAfterShow = (treeRef: Ref, isFailed = true) => {
if (isFailed) {
todoToolPreviewNodeTreeRef.value?.close()
} else {
failedToolPreviewNodeTreeRef.value?.close()
}
}, {
immediate: true,
});
handleNodeTreeAfterShow(treeRef, isFailed)
}

const handleNodeTreeAfterShow = (treeRef: Ref, isFailed = true) => {
setTimeout(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,16 @@
</template>
<template
v-else-if="
content.status === 'RUNNING' &&
content.flow_type === 'INNER_FLOW' &&
content.todos.length > 0 &&
content.todos.every((todoItem) => todoItem.type !== 'RESOURCE_REPLENISH')
">
{{ t('任务待确认') }}
<span
:style="{
color: getStatusColor(content.status) || '#63656e',
}">
{{ getStatusText(content.status) || content.summary }}
</span>
</template>
<template v-else-if="isPause && isTodos === false">
<span>{{ t('处理人') }}: </span>
Expand Down Expand Up @@ -293,6 +297,25 @@
// return `${expireTime * 24} ${t('小时')}`;
// });

const getStatusText = (status: string) => {
const infoMap: Record<string, string> = {
SUCCEEDED: t('任务_执行成功'),
FAILED: t('任务_执行失败'),
RUNNING: t('任务_待确认'),
};
return infoMap[status] ? infoMap[status] : null;
};

const getStatusColor = (status: string) => {
const infoMap: Record<string, string> = {
SUCCEEDED: '#14a568',
FAILED: '#ea3636',
RUNNING: '#ff9c01',
TERMINATED: '#ea3636',
};
return infoMap[status] ? infoMap[status] : null;
};

const handleConfirmTerminal = (item: FlowItem) => {
btnState.terminateLoading = true;
revokeTicketFlow({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,9 @@
<div
v-else
class="flow-todo__infos">
{{ item.done_by }} {{ t('处理完成') }}, {{ t('操作') }}:<span
:class="String(item.status).toLowerCase()"
>{{ getOperation(item) }}</span
>, {{ t('耗时') }}:{{ getCostTimeDisplay(item.cost_time) }}
{{ item.done_by }} {{ t('处理完成') }}, {{ t('操作') }}:
<span :class="String(item.status).toLowerCase()">{{ getOperation(item) }} </span>
, {{ t('耗时') }}:{{ getCostTimeDisplay(item.cost_time) }}
<template v-if="content.url">
,<a :href="content.url">{{ t('查看详情') }} &gt;</a>
</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
<template>
<div>
<template v-if="content.status === 'RUNNING'">
{{ t('任务待确认') }}
<span style="color: #ff9c01">{{ t('任务“待确认”') }}</span>
</template>
<template v-else>
<span
:style="{
color: content.status === 'TERMINATED' ? '#ea3636' : '#63656e',
color: getStatusColor(content.status) || '#63656e',
}">
{{ content.summary }}
{{ getStatusText(content.status) || content.summary }}
</span>
<template v-if="content.err_msg">
<span>,{{ t('处理人') }}: </span>
Expand Down Expand Up @@ -69,4 +69,21 @@
defineProps<Props>();

const { t } = useI18n();

const getStatusText = (status: string) => {
const infoMap: Record<string, string> = {
SUCCEEDED: t('任务_执行成功'),
FAILED: t('任务_执行失败'),
};
return infoMap[status] ? infoMap[status] : null;
};

const getStatusColor = (status: string) => {
const infoMap: Record<string, string> = {
SUCCEEDED: '#14a568',
FAILED: '#ea3636',
TERMINATED: '#ea3636',
};
return infoMap[status] ? infoMap[status] : null;
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,9 @@
<div
v-else
class="flow-todo__infos">
{{ data.done_by }} {{ t('处理完成') }}, {{ t('操作') }}:<span :class="String(data.status).toLowerCase()">{{
getOperation(data)
}}</span
>, {{ t('耗时') }}:{{ getCostTimeDisplay(data.cost_time) }}
{{ data.done_by }} {{ t('处理完成') }}, {{ t('操作') }}:
<span :class="String(data.status).toLowerCase()">{{ getOperation(data) }} </span>
, {{ t('耗时') }}:{{ getCostTimeDisplay(data.cost_time) }}
<template v-if="content.url">
,<a :href="content.url">{{ t('查看详情') }} &gt;</a>
</template>
Expand Down

0 comments on commit 95d22a5

Please sign in to comment.