CMVR-IOT-UI/src/views/flow/nodes/function/subFlow.vue
lixiaolong b3dae8db39 feat(flow): 添加子流程功能并优化参数引用逻辑
- 新增子流程节点类型,支持在同一项目中执行已发布工作流
- 添加子流程节点UI组件和相关配置选项
- 重构参数引用逻辑,使用getUpstreamInput替代getInput方法
- 优化cascader组件属性设置,统一使用props配置checkStrictly
- 修正多个参数组件中的handleTypeChange和cascaderChange函数参数传递
- 添加流程输出参数管理功能,支持引用来源选择和类型识别
- 实现子流程运行时状态管理和迭代输出处理
- 增加循环引用检测和资源验证功能
- 更新API接口,添加子流程选项获取方法
- 修复流程引用和依赖关系处理逻辑
2026-08-21 11:48:10 +08:00

98 lines
3.2 KiB
Vue

<template>
<div class="node__container" :class="props.model.id">
<NodeState
ref="nodeStateRef"
:state="nodeOperatingStatus"
:runtimes="runtimes"
:popover-width="760"
popper-class="flow-result-popover flow-subflow-result-popover"
>
<template #input>
<JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
</template>
<template #output>
<SubFlowExecutionResults v-if="nodeOperatingStatus !== 'FAILED'" :data="subFlowExecution" />
<div v-else class="subflow-error">{{ errorInfoData }}</div>
</template>
</NodeState>
<NodeTitle
:icon="props.properties.icon"
:node-id="props.model.id"
:node-properties="props.properties"
:node-type="props.properties.nodeType || 'NONE'"
:node-name="props.properties.name"
:node-desc="props.properties.desc"
@set-node-name="setNodeName"
/>
</div>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue'
import NodeState from '../../components/NodeState.vue'
import NodeTitle from '../../components/NodeTitle.vue'
import SubFlowExecutionResults from '../../components/SubFlowExecutionResults.vue'
import { useFlowEvents } from '../../composables/useFlowEvents'
const props = defineProps({ model: Object, properties: Object })
const emits = defineEmits(['contentChange'])
const { onFlowEvent } = useFlowEvents()
const nodeStateRef = ref(null)
const nodeOperatingStatus = ref('NORMAL')
const runtimes = ref(0)
const inputJsonData = ref({})
const outputJsonData = ref({})
const errorInfoData = ref('')
const subFlowExecution = computed(() => outputJsonData.value?.subFlowExecution || {
name: props.properties?.subFlow?.detectName || props.properties?.name,
versionNo: props.properties?.subFlow?.versionNo,
output: outputJsonData.value,
executions: [],
})
const parseValue = (value) => {
if (!value) return {}
if (typeof value === 'object') return value
try { return JSON.parse(value) || {} } catch { return value }
}
const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id)
lf.setProperties(props.model.id, { ...properties, name })
emits('contentChange')
}
onMounted(() => {
onFlowEvent('changeNodeState', (data) => {
if (data.nodeId !== props.model.id) return
nodeOperatingStatus.value = data.status
runtimes.value = data.endTime && data.startTime ? data.endTime - data.startTime : 0
inputJsonData.value = parseValue(data.paramsIn)
outputJsonData.value = parseValue(data.paramsOut)
errorInfoData.value = data?.message || ''
emits('contentChange')
})
onFlowEvent('contentChange', (data) => {
if (data.id !== props.model.id) return
nodeOperatingStatus.value = 'NORMAL'
inputJsonData.value = {}
outputJsonData.value = {}
emits('contentChange')
})
})
defineExpose({ closePopover: () => nodeStateRef.value?.closePopover?.() })
</script>
<style scoped lang="scss">
.node__container { width: 100%; height: auto; }
.subflow-error { color: var(--el-color-danger); line-height: 20px; overflow-wrap: anywhere; }
</style>
<style lang="scss">
.flow-subflow-result-popover {
max-width: min(760px, calc(100vw - 32px));
.result-section__content { max-height: 560px; }
}
</style>