<template>
|
<ElDrawer
|
:model-value="visible"
|
title="流程图查看"
|
size="92%"
|
destroy-on-close
|
@update:model-value="handleVisibleChange"
|
>
|
<div class="flex h-[calc(100vh-160px)] flex-col gap-4">
|
<ElCard shadow="never" class="shrink-0">
|
<div class="flex items-start justify-between gap-4">
|
<div class="min-w-0">
|
<div class="text-base font-semibold text-[var(--art-text-primary)]">
|
{{ detail.templateName || detail.templateCode || '--' }}
|
</div>
|
<div class="mt-1 text-sm text-[var(--art-text-secondary)]">
|
模板编码 {{ detail.templateCode || '--' }},起点 {{ detail.sourceType || '--' }},终点
|
{{ detail.targetType || '--' }}
|
</div>
|
</div>
|
<ElSpace wrap>
|
<ElTag :type="detail.statusType || 'info'" effect="light">
|
{{ detail.statusText || '--' }}
|
</ElTag>
|
<ElTag :type="detail.isCurrentType || 'info'" effect="light">
|
{{ detail.isCurrentText || '--' }}
|
</ElTag>
|
</ElSpace>
|
</div>
|
</ElCard>
|
|
<div class="grid min-h-0 flex-1 gap-4 xl:grid-cols-3">
|
<ElCard shadow="never" class="min-h-0">
|
<template #header>
|
<div class="flex items-center justify-between gap-3">
|
<span class="font-medium">模板节点</span>
|
<span class="text-xs text-[var(--art-text-secondary)]">
|
{{ nodeLoading ? '加载中' : `第 ${nodePagination.current} 页 / 共 ${nodePagination.total} 条` }}
|
</span>
|
</div>
|
</template>
|
|
<div class="flex h-[calc(100vh-300px)] flex-col">
|
<ElSkeleton v-if="loading || nodeLoading" :rows="8" animated />
|
<ElEmpty
|
v-else-if="nodeRows.length === 0"
|
description="暂无节点数据"
|
:image-size="100"
|
/>
|
<template v-else>
|
<ElTable
|
:data="nodeRows"
|
border
|
highlight-current-row
|
height="100%"
|
:current-row-key="selectedNodeId"
|
row-key="id"
|
@current-change="handleNodeClick"
|
>
|
<ElTableColumn prop="nodeOrder" label="顺序" width="72" align="center" />
|
<ElTableColumn prop="nodeCode" label="节点编码" min-width="140" show-overflow-tooltip />
|
<ElTableColumn prop="nodeName" label="节点名称" min-width="160" show-overflow-tooltip />
|
<ElTableColumn prop="systemCode" label="系统编码" min-width="140" show-overflow-tooltip />
|
</ElTable>
|
<div class="mt-3 flex justify-end">
|
<ElPagination
|
small
|
background
|
layout="prev, pager, next"
|
:current-page="nodePagination.current"
|
:page-size="nodePagination.pageSize"
|
:total="nodePagination.total"
|
@current-change="handleNodePageChange"
|
/>
|
</div>
|
</template>
|
</div>
|
</ElCard>
|
|
<ElCard shadow="never" class="min-h-0">
|
<template #header>
|
<div class="flex items-center justify-between gap-3">
|
<span class="font-medium">子系统流程</span>
|
<span class="text-xs text-[var(--art-text-secondary)]">
|
{{
|
flowLoading
|
? '加载中'
|
: selectedNodeId
|
? `第 ${flowPagination.current} 页 / 共 ${flowPagination.total} 条`
|
: '待选择节点'
|
}}
|
</span>
|
</div>
|
</template>
|
|
<div class="flex h-[calc(100vh-300px)] flex-col">
|
<div
|
v-if="!selectedNodeId"
|
class="flex h-full items-center justify-center text-sm text-[var(--art-text-secondary)]"
|
>
|
请先选择左侧模板节点
|
</div>
|
<ElSkeleton v-else-if="flowLoading" :rows="8" animated />
|
<ElEmpty
|
v-else-if="flowRows.length === 0"
|
description="暂无流程数据"
|
:image-size="100"
|
/>
|
<template v-else>
|
<ElTable
|
:data="flowRows"
|
border
|
highlight-current-row
|
height="100%"
|
:current-row-key="selectedFlowId"
|
row-key="id"
|
@current-change="handleFlowClick"
|
>
|
<ElTableColumn prop="flowCode" label="流程编码" min-width="160" show-overflow-tooltip />
|
<ElTableColumn prop="flowName" label="流程名称" min-width="180" show-overflow-tooltip />
|
<ElTableColumn prop="systemCode" label="系统编码" min-width="140" show-overflow-tooltip />
|
</ElTable>
|
<div class="mt-3 flex justify-end">
|
<ElPagination
|
small
|
background
|
layout="prev, pager, next"
|
:current-page="flowPagination.current"
|
:page-size="flowPagination.pageSize"
|
:total="flowPagination.total"
|
@current-change="handleFlowPageChange"
|
/>
|
</div>
|
</template>
|
</div>
|
</ElCard>
|
|
<ElCard shadow="never" class="min-h-0">
|
<template #header>
|
<div class="flex items-center justify-between gap-3">
|
<span class="font-medium">流程步骤</span>
|
<span class="text-xs text-[var(--art-text-secondary)]">
|
{{
|
stepLoading
|
? '加载中'
|
: selectedFlowId
|
? `第 ${stepPagination.current} 页 / 共 ${stepPagination.total} 条`
|
: '待选择流程'
|
}}
|
</span>
|
</div>
|
</template>
|
|
<div class="flex h-[calc(100vh-300px)] flex-col">
|
<div
|
v-if="!selectedFlowId"
|
class="flex h-full items-center justify-center text-sm text-[var(--art-text-secondary)]"
|
>
|
请先选择中间子系统流程
|
</div>
|
<ElSkeleton v-else-if="stepLoading" :rows="8" animated />
|
<ElEmpty
|
v-else-if="stepRows.length === 0"
|
description="暂无步骤数据"
|
:image-size="100"
|
/>
|
<template v-else>
|
<ElTable :data="stepRows" border height="100%" row-key="id">
|
<ElTableColumn prop="stepOrder" label="顺序" width="72" align="center" />
|
<ElTableColumn prop="stepCode" label="步骤编码" min-width="140" show-overflow-tooltip />
|
<ElTableColumn prop="stepName" label="步骤名称" min-width="180" show-overflow-tooltip />
|
<ElTableColumn prop="stepType" label="步骤类型" min-width="140" show-overflow-tooltip />
|
</ElTable>
|
<div class="mt-3 flex justify-end">
|
<ElPagination
|
small
|
background
|
layout="prev, pager, next"
|
:current-page="stepPagination.current"
|
:page-size="stepPagination.pageSize"
|
:total="stepPagination.total"
|
@current-change="handleStepPageChange"
|
/>
|
</div>
|
</template>
|
</div>
|
</ElCard>
|
</div>
|
</div>
|
</ElDrawer>
|
</template>
|
|
<script setup>
|
import { computed, ref, watch } from 'vue'
|
import { ElMessage } from 'element-plus'
|
import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
|
import {
|
fetchTaskPathTemplateNodePage
|
} from '@/api/task-path-template-node'
|
import { fetchSubsystemFlowTemplatePage } from '@/api/subsystem-flow-template'
|
import { fetchFlowStepTemplatePage } from '@/api/flow-step-template'
|
|
const props = defineProps({
|
visible: { type: Boolean, default: false },
|
loading: { type: Boolean, default: false },
|
detail: { type: Object, default: () => ({}) }
|
})
|
|
const emit = defineEmits(['update:visible'])
|
|
const visible = computed({
|
get: () => props.visible,
|
set: (value) => emit('update:visible', value)
|
})
|
|
const nodeLoading = ref(false)
|
const flowLoading = ref(false)
|
const stepLoading = ref(false)
|
const nodeRows = ref([])
|
const flowRows = ref([])
|
const stepRows = ref([])
|
const selectedNodeId = ref(null)
|
const selectedFlowId = ref(null)
|
const DEFAULT_PAGE_SIZE = 20
|
const nodePagination = ref({ current: 1, pageSize: DEFAULT_PAGE_SIZE, total: 0 })
|
const flowPagination = ref({ current: 1, pageSize: DEFAULT_PAGE_SIZE, total: 0 })
|
const stepPagination = ref({ current: 1, pageSize: DEFAULT_PAGE_SIZE, total: 0 })
|
|
function normalizeRecords(response) {
|
return Array.isArray(response?.records) ? response.records : []
|
}
|
|
function normalizeTotal(response) {
|
const total = Number(response?.total)
|
return Number.isNaN(total) ? 0 : total
|
}
|
|
function resetFlowState() {
|
nodeRows.value = []
|
flowRows.value = []
|
stepRows.value = []
|
selectedNodeId.value = null
|
selectedFlowId.value = null
|
nodePagination.value.current = 1
|
nodePagination.value.total = 0
|
flowPagination.value.current = 1
|
flowPagination.value.total = 0
|
stepPagination.value.current = 1
|
stepPagination.value.total = 0
|
}
|
|
async function loadStepRows(flowId, current = stepPagination.value.current) {
|
if (!flowId) {
|
stepRows.value = []
|
selectedFlowId.value = null
|
stepPagination.value.total = 0
|
return
|
}
|
|
stepLoading.value = true
|
try {
|
const response = await guardRequestWithMessage(
|
fetchFlowStepTemplatePage({
|
current,
|
pageSize: stepPagination.value.pageSize,
|
flowId
|
}),
|
{ records: [] },
|
{ timeoutMessage: '流程步骤加载超时,已停止等待' }
|
)
|
stepRows.value = normalizeRecords(response)
|
stepPagination.value.current = current
|
stepPagination.value.total = normalizeTotal(response)
|
} catch (error) {
|
stepRows.value = []
|
stepPagination.value.total = 0
|
ElMessage.error(error?.message || '流程步骤加载失败')
|
} finally {
|
stepLoading.value = false
|
}
|
}
|
|
async function loadFlowRows(node, current = flowPagination.value.current) {
|
if (!node?.nodeCode) {
|
flowRows.value = []
|
stepRows.value = []
|
selectedFlowId.value = null
|
flowPagination.value.total = 0
|
stepPagination.value.total = 0
|
return
|
}
|
|
flowLoading.value = true
|
try {
|
const response = await guardRequestWithMessage(
|
fetchSubsystemFlowTemplatePage({
|
current,
|
pageSize: flowPagination.value.pageSize,
|
flowCode: node.nodeCode
|
}),
|
{ records: [] },
|
{ timeoutMessage: '子系统流程加载超时,已停止等待' }
|
)
|
flowRows.value = normalizeRecords(response)
|
flowPagination.value.current = current
|
flowPagination.value.total = normalizeTotal(response)
|
selectedFlowId.value = null
|
stepRows.value = []
|
stepPagination.value.current = 1
|
stepPagination.value.total = 0
|
} catch (error) {
|
flowRows.value = []
|
stepRows.value = []
|
selectedFlowId.value = null
|
flowPagination.value.total = 0
|
stepPagination.value.total = 0
|
ElMessage.error(error?.message || '子系统流程加载失败')
|
} finally {
|
flowLoading.value = false
|
}
|
}
|
|
async function loadNodeRows(templateId, current = nodePagination.value.current) {
|
if (!templateId) {
|
resetFlowState()
|
return
|
}
|
|
nodeLoading.value = true
|
try {
|
const response = await guardRequestWithMessage(
|
fetchTaskPathTemplateNodePage({
|
current,
|
pageSize: nodePagination.value.pageSize,
|
templateId
|
}),
|
{ records: [] },
|
{ timeoutMessage: '模板节点加载超时,已停止等待' }
|
)
|
nodeRows.value = normalizeRecords(response)
|
nodePagination.value.current = current
|
nodePagination.value.total = normalizeTotal(response)
|
selectedNodeId.value = null
|
flowRows.value = []
|
stepRows.value = []
|
flowPagination.value.current = 1
|
flowPagination.value.total = 0
|
stepPagination.value.current = 1
|
stepPagination.value.total = 0
|
} catch (error) {
|
resetFlowState()
|
ElMessage.error(error?.message || '模板节点加载失败')
|
} finally {
|
nodeLoading.value = false
|
}
|
}
|
|
function handleNodeClick(node) {
|
if (!node || selectedNodeId.value === node.id) return
|
selectedNodeId.value = node.id
|
selectedFlowId.value = null
|
stepRows.value = []
|
flowPagination.value.current = 1
|
stepPagination.value.current = 1
|
loadFlowRows(node)
|
}
|
|
function handleFlowClick(flow) {
|
if (!flow || selectedFlowId.value === flow.id) return
|
selectedFlowId.value = flow.id
|
stepPagination.value.current = 1
|
loadStepRows(flow.id)
|
}
|
|
function handleNodePageChange(current) {
|
loadNodeRows(props.detail?.id, current)
|
}
|
|
function handleFlowPageChange(current) {
|
const node = nodeRows.value.find((item) => item.id === selectedNodeId.value)
|
if (!node) return
|
loadFlowRows(node, current)
|
}
|
|
function handleStepPageChange(current) {
|
if (!selectedFlowId.value) return
|
loadStepRows(selectedFlowId.value, current)
|
}
|
|
function handleVisibleChange(value) {
|
visible.value = value
|
}
|
|
watch(
|
() => [props.visible, props.detail?.id],
|
([isVisible, detailId]) => {
|
if (isVisible && detailId) {
|
loadNodeRows(detailId)
|
}
|
if (!isVisible) {
|
resetFlowState()
|
}
|
},
|
{ immediate: true }
|
)
|
</script>
|