feat: 流程添加注释

This commit is contained in:
zhanghao 2026-08-07 14:38:16 +08:00
parent 8e2afcbaa6
commit 6c9ead2603
37 changed files with 1107 additions and 7 deletions

View File

@ -1,3 +1,7 @@
<!--
* 文件说明节点组件库侧栏负责分类搜索和拖拽创建
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="component-library"> <div class="component-library">
<div class="library-header"> <div class="library-header">
@ -75,6 +79,11 @@ watch(keyword, (value) => {
if (value.trim()) activeNames.value = filteredGroups.value.map((group) => group.collapseTitle); if (value.trim()) activeNames.value = filteredGroups.value.map((group) => group.collapseTitle);
}); });
/**
* 处理 handleDragCustom 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} event 触发操作的浏览器事件
* @param {*} node 当前流程节点
*/
const handleDragCustom = (event, node) => { const handleDragCustom = (event, node) => {
event.dataTransfer.effectAllowed = "copy"; event.dataTransfer.effectAllowed = "copy";
event.dataTransfer.setData("flowNode", JSON.stringify(node)); event.dataTransfer.setData("flowNode", JSON.stringify(node));

View File

@ -1,3 +1,7 @@
<!--
* 文件说明递归参数表单负责嵌套字段的增删和类型切换
* 作用范围仅服务于流程设计器模块
-->
<!-- components/FormItemRecursive.vue --> <!-- components/FormItemRecursive.vue -->
<template> <template>
<div class="form-item-recursive"> <div class="form-item-recursive">
@ -147,6 +151,10 @@ const { formType, currentList, propPath, depth, isFirstLevel, endDepth, parentPa
const emit = defineEmits(['add-item', 'delete-item']) const emit = defineEmits(['add-item', 'delete-item'])
// //
/**
* 处理 handleTypeChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} item 调用方传入的 item 参数
*/
const handleTypeChange = (item) => { const handleTypeChange = (item) => {
if (!["object", "array<object>"].includes(item.type)) { if (!["object", "array<object>"].includes(item.type)) {
item.children = []; // item.children = []; //
@ -156,6 +164,10 @@ const handleTypeChange = (item) => {
}; };
// //
/**
* 处理 handleAddChild 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} parentItem 调用方传入的 parentItem 参数
*/
const handleAddChild = (parentItem) => { const handleAddChild = (parentItem) => {
parentItem.children.push({ parentItem.children.push({
name: "", name: "",
@ -168,6 +180,10 @@ const handleAddChild = (parentItem) => {
}; };
// //
/**
* 处理 handleDelete 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} index 目标项索引
*/
const handleDelete = (index) => { const handleDelete = (index) => {
// = + parentPathundefined // = + parentPathundefined
const fullPath = parentPath ? [...parentPath, index] : [index]; const fullPath = parentPath ? [...parentPath, index] : [index];
@ -175,6 +191,10 @@ const handleDelete = (index) => {
} }
// //
/**
* 处理 handleChildDelete 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} childFullPath 调用方传入的 childFullPath 参数
*/
const handleChildDelete = (childFullPath) => { const handleChildDelete = (childFullPath) => {
emit("delete-item", childFullPath); emit("delete-item", childFullPath);
} }

View File

@ -1,3 +1,7 @@
<!--
* 文件说明节点运行状态面板展示耗时输入输出和错误
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div v-if="showState !== 'NORMAL'" class="node-state" :class="`node-state--${showState.toLowerCase()}`"> <div v-if="showState !== 'NORMAL'" class="node-state" :class="`node-state--${showState.toLowerCase()}`">
<div class="node-state__summary"> <div class="node-state__summary">
@ -66,6 +70,9 @@ watch(() => props.state, (value) => {
showState.value = value; showState.value = value;
}, { immediate: true }); }, { immediate: true });
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
showState.value = "NORMAL"; showState.value = "NORMAL";
popoverVisible.value = false; popoverVisible.value = false;

View File

@ -1,3 +1,7 @@
<!--
* 文件说明节点标题栏负责重命名删除和单节点执行
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node-title"> <div class="node-title">
<div class="node-title__main"> <div class="node-title__main">
@ -108,12 +112,18 @@ const typeLabel = computed(() => {
return { EDGE: "设备", LLM: "模型", AE: "评估" }[props.nodeType] || props.nodeType; return { EDGE: "设备", LLM: "模型", AE: "评估" }[props.nodeType] || props.nodeType;
}); });
/**
* 处理 sourceName 对应的数据或交互作用范围仅限当前组件或模块
*/
const sourceName = () => props.nodeProperties?.name || props.nodeName || "未命名节点"; const sourceName = () => props.nodeProperties?.name || props.nodeName || "未命名节点";
watch(sourceName, (value) => { watch(sourceName, (value) => {
if (!isEditing.value) localName.value = value; if (!isEditing.value) localName.value = value;
}); });
/**
* 处理 startEditing 对应的数据或交互作用范围仅限当前组件或模块
*/
const startEditing = async () => { const startEditing = async () => {
isEditing.value = true; isEditing.value = true;
await nextTick(); await nextTick();
@ -121,6 +131,9 @@ const startEditing = async () => {
nameInputRef.value?.select?.(); nameInputRef.value?.select?.();
}; };
/**
* 确认 confirmNodeName 对应的数据或交互作用范围仅限当前组件或模块
*/
const confirmNodeName = () => { const confirmNodeName = () => {
const name = localName.value.trim(); const name = localName.value.trim();
if (!name) return; if (!name) return;
@ -129,11 +142,17 @@ const confirmNodeName = () => {
isEditing.value = false; isEditing.value = false;
}; };
/**
* 处理 cancelNodeName 对应的数据或交互作用范围仅限当前组件或模块
*/
const cancelNodeName = () => { const cancelNodeName = () => {
localName.value = sourceName(); localName.value = sourceName();
isEditing.value = false; isEditing.value = false;
}; };
/**
* 删除 deleteNode 对应的数据或交互作用范围仅限当前组件或模块
*/
const deleteNode = async () => { const deleteNode = async () => {
try { try {
await ElMessageBox.confirm( await ElMessageBox.confirm(
@ -155,6 +174,9 @@ const deleteNode = async () => {
} }
}; };
/**
* 执行 execute 对应的数据或交互作用范围仅限当前组件或模块
*/
const execute = () => { const execute = () => {
document.dispatchEvent(new CustomEvent("singleNodeExecution", { document.dispatchEvent(new CustomEvent("singleNodeExecution", {
bubbles: false, bubbles: false,

View File

@ -1,3 +1,7 @@
<!--
* 文件说明动态节点包装器挂载具体节点并同步内容变化
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__box"> <div class="node__box">
<component :is="componentId" :model="props.model" :properties="props.properties" ref="nodeRef" @contentChange="contentChange"></component> <component :is="componentId" :model="props.model" :properties="props.properties" ref="nodeRef" @contentChange="contentChange"></component>
@ -18,6 +22,9 @@ const emits = defineEmits(['contentChange', 'bindRef'])
const componentId = ref(props.component) const componentId = ref(props.component)
/**
* 处理 contentChange 对应的数据或交互作用范围仅限当前组件或模块
*/
const contentChange = () => { const contentChange = () => {
emits('contentChange') emits('contentChange')
} }
@ -40,4 +47,4 @@ onMounted(() => {
box-shadow: 0 5px 15px 0#00000008; box-shadow: 0 5px 15px 0#00000008;
position: relative; position: relative;
} }
</style> </style>

View File

@ -1,3 +1,7 @@
<!--
* 文件说明节点参数抽屉统一触发参数校验和保存
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-drawer <el-drawer
:model-value="props.drawer" :model-value="props.drawer"
@ -55,6 +59,9 @@ const currentComponent = computed(() => {
}) })
// //
/**
* 确认 confirmSave 对应的数据或交互作用范围仅限当前组件或模块
*/
const confirmSave = async () => { const confirmSave = async () => {
if (paramsComponentRef.value && typeof paramsComponentRef.value.validateAndSave === 'function') { if (paramsComponentRef.value && typeof paramsComponentRef.value.validateAndSave === 'function') {
await paramsComponentRef.value.validateAndSave() await paramsComponentRef.value.validateAndSave()
@ -67,6 +74,9 @@ const confirmSave = async () => {
defineExpose({ confirmSave }) defineExpose({ confirmSave })
// / // /
/**
* 处理 handleSaveSuccess 对应的数据或交互作用范围仅限当前组件或模块
*/
const handleSaveSuccess = () => { const handleSaveSuccess = () => {
emitter.emit('setProperties', { id: props.data.id }) emitter.emit('setProperties', { id: props.data.id })
emitter.emit("throwAnError", { id: props.data.id, hasError: false, type: props.data.type }); emitter.emit("throwAnError", { id: props.data.id, hasError: false, type: props.data.type });
@ -74,6 +84,9 @@ const handleSaveSuccess = () => {
emits('close') emits('close')
} }
/**
* 处理 handleSaveError 对应的数据或交互作用范围仅限当前组件或模块
*/
const handleSaveError = () => { const handleSaveError = () => {
emitter.emit('setProperties', { id: props.data.id }) emitter.emit('setProperties', { id: props.data.id })
emitter.emit("throwAnError", { id: props.data.id, hasError: true, type: props.data.type }); emitter.emit("throwAnError", { id: props.data.id, hasError: true, type: props.data.type });

View File

@ -1,3 +1,7 @@
<!--
* 文件说明流程试运行抽屉收集运行参数并绑定机器人设备
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-drawer <el-drawer
:model-value="props.drawer" :model-value="props.drawer"
@ -53,7 +57,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-else-if="row.type !== 'object' && !row.type.includes('array')" label="" :prop="`tableData${row.propPath}value`" :rules="row.required ? [{ required: true, message: '请输入变量名', trigger: 'blur' }] : []"> <el-form-item v-else-if="row.type !== 'object' && !row.type.includes('array')" label="" :prop="`tableData${row.propPath}value`" :rules="row.required ? [{ required: true, message: '请输入变量名', trigger: 'blur' }] : []">
<el-input v-if="row.type === 'string'" v-model="row.value" /> <el-input v-if="row.type === 'string'" v-model="row.value" />
<el-input-number v-if="row.type === 'number'" :controls="false" v-model="row.value" /> <el-input-number v-if="row.type === 'number'" :controls="false" v-model="row.value" />
@ -93,14 +97,27 @@ const tableData = ref([])
// 使 // 使
const trialRunCache = new Map() const trialRunCache = new Map()
const bindingLoading = ref(false) const bindingLoading = ref(false)
/**
* 处理 emptyBindingSummary 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} robotId 机器人 ID
*/
const emptyBindingSummary = (robotId = '') => ({ robotId, matched: 0, missing: 0, untouched: 0 }) const emptyBindingSummary = (robotId = '') => ({ robotId, matched: 0, missing: 0, untouched: 0 })
const bindingSummary = ref(emptyBindingSummary()) const bindingSummary = ref(emptyBindingSummary())
const emits = defineEmits(['close', 'changeState']) const emits = defineEmits(['close', 'changeState'])
/**
* 克隆 cloneData 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} data 待处理的数据
*/
const cloneData = (data) => JSON.parse(JSON.stringify(data || [])) const cloneData = (data) => JSON.parse(JSON.stringify(data || []))
// //
/**
* 合并 mergeCachedValues 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} source 源数据
* @param {*} cached 缓存数据
*/
const mergeCachedValues = (source, cached) => { const mergeCachedValues = (source, cached) => {
const cachedByName = new Map((cached || []).map(item => [item.name, item])) const cachedByName = new Map((cached || []).map(item => [item.name, item]))
return (source || []).map((item, index) => { return (source || []).map((item, index) => {
@ -115,14 +132,23 @@ const mergeCachedValues = (source, cached) => {
}) })
} }
/**
* 处理 cacheKey 对应的数据或交互作用范围仅限当前组件或模块
*/
const cacheKey = () => props.flowId || '__new_flow__' const cacheKey = () => props.flowId || '__new_flow__'
// //
/**
* 缓存 rememberTrialRunParams 对应的数据或交互作用范围仅限当前组件或模块
*/
const rememberTrialRunParams = () => { const rememberTrialRunParams = () => {
if (!tableData.value.length) return if (!tableData.value.length) return
trialRunCache.set(cacheKey(), cloneData(tableData.value)) trialRunCache.set(cacheKey(), cloneData(tableData.value))
} }
/**
* 处理 handleClose 对应的数据或交互作用范围仅限当前组件或模块
*/
const handleClose = () => { const handleClose = () => {
rememberTrialRunParams() rememberTrialRunParams()
ruleFormRef.value?.clearValidate() ruleFormRef.value?.clearValidate()
@ -142,6 +168,9 @@ watch(() => props.drawer,
} }
) )
/**
* 确认 confirm 对应的数据或交互作用范围仅限当前组件或模块
*/
const confirm = () => { const confirm = () => {
rememberTrialRunParams() rememberTrialRunParams()
lf.fitView() lf.fitView()
@ -174,7 +203,13 @@ const confirm = () => {
const robotIdOptions = ref([]) const robotIdOptions = ref([])
/**
* 处理 handleRobotChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} robotId 机器人 ID
*/
const handleRobotChange = async (robotId) => { const handleRobotChange = async (robotId) => {
//
//
bindingSummary.value = emptyBindingSummary(robotId || '') bindingSummary.value = emptyBindingSummary(robotId || '')
if (!robotId) return if (!robotId) return
bindingLoading.value = true bindingLoading.value = true

View File

@ -1,3 +1,7 @@
<!--
* 文件说明通用节点参数面板配置输入输出及机器人动作调试
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-collapse v-model="activeNames"> <el-collapse v-model="activeNames">
<!-- 输入参数 --> <!-- 输入参数 -->
@ -142,6 +146,11 @@ const activeNames = ref(['1', '2'])
const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id) const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id)
// //
/**
* 新增 addFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
* @param {*} type 目标类型
*/
const addFormItem = (e, type) => { const addFormItem = (e, type) => {
e.stopPropagation() e.stopPropagation()
const obj = { const obj = {
@ -156,11 +165,20 @@ const addFormItem = (e, type) => {
} }
// //
/**
* 处理 handleDelete 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} index 目标项索引
*/
const handleDelete = (index) => { const handleDelete = (index) => {
formData.nodeParams.splice(index, 1) formData.nodeParams.splice(index, 1)
} }
// FormItemRecursive emit // FormItemRecursive emit
/**
* 删除 deleteTopLevelItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} fullPath 字段完整路径
* @param {*} propPath 字段校验路径
*/
const deleteTopLevelItem = (fullPath, propPath) => { const deleteTopLevelItem = (fullPath, propPath) => {
let currentLevel = formData[propPath] let currentLevel = formData[propPath]
for (let i = 0; i < fullPath.length - 1; i++) { for (let i = 0; i < fullPath.length - 1; i++) {
@ -171,6 +189,9 @@ const deleteTopLevelItem = (fullPath, propPath) => {
} }
// //
/**
* 初始化 initData 对应的数据或交互作用范围仅限当前组件或模块
*/
const initData = () => { const initData = () => {
const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || [])) const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || []))
const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || [])) const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || []))
@ -187,6 +208,9 @@ watch(
) )
// //
/**
* 校验 validateAndSave 对应的数据或交互作用范围仅限当前组件或模块
*/
const validateAndSave = async () => { const validateAndSave = async () => {
let inputValid = true let inputValid = true
let outputValid = true let outputValid = true
@ -224,6 +248,9 @@ const robotOptions = ref([])
const deviceOptions = ref([]) const deviceOptions = ref([])
const deviceLoading = ref(false) const deviceLoading = ref(false)
/**
* 加载 loadRobotOptions 对应的数据或交互作用范围仅限当前组件或模块
*/
const loadRobotOptions = async () => { const loadRobotOptions = async () => {
const response = await getRobotList({ pageNum: 1, pageSize: 1000, connectStatus: '1' }) const response = await getRobotList({ pageNum: 1, pageSize: 1000, connectStatus: '1' })
robotOptions.value = (response.rows || []).map(robot => ({ robotOptions.value = (response.rows || []).map(robot => ({
@ -232,6 +259,10 @@ const loadRobotOptions = async () => {
})) }))
} }
/**
* 加载 loadRobotDevices 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} robotId 机器人 ID
*/
const loadRobotDevices = async (robotId) => { const loadRobotDevices = async (robotId) => {
robotForm.deviceId = '' robotForm.deviceId = ''
deviceOptions.value = [] deviceOptions.value = []
@ -250,6 +281,10 @@ const loadRobotDevices = async (robotId) => {
} }
} }
/**
* 测试 testRule 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} property 参数属性
*/
const testRule = (property) => { const testRule = (property) => {
if (property?.name === 'stationId' && props.data.properties.action === 'AGV_MOVE_TO_STATION') { if (property?.name === 'stationId' && props.data.properties.action === 'AGV_MOVE_TO_STATION') {
return [ return [
@ -311,6 +346,9 @@ const robotDialogTitle = computed(() => {
return '选择机器人设备' return '选择机器人设备'
}) })
/**
* 处理 submitRobotForm 对应的数据或交互作用范围仅限当前组件或模块
*/
const submitRobotForm = () => { const submitRobotForm = () => {
if (robotFormAction.value === 'AGV_MOVE_TO_POINT') { if (robotFormAction.value === 'AGV_MOVE_TO_POINT') {
robotFormRef.value.validate(async (valid) => { robotFormRef.value.validate(async (valid) => {
@ -440,6 +478,10 @@ const submitRobotForm = () => {
} }
} }
/**
* 处理 toStationOptions 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} stations 站点集合
*/
const toStationOptions = (stations) => (Array.isArray(stations) ? stations : []) const toStationOptions = (stations) => (Array.isArray(stations) ? stations : [])
.filter(station => station?.id !== undefined && station?.id !== null && String(station.id).trim()) .filter(station => station?.id !== undefined && station?.id !== null && String(station.id).trim())
.map(station => { .map(station => {
@ -451,6 +493,10 @@ const toStationOptions = (stations) => (Array.isArray(stations) ? stations : [])
} }
}) })
/**
* 打开 openRobotForm 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} action 节点动作类型
*/
const openRobotForm = async (action) => { const openRobotForm = async (action) => {
dialogVisible.value = true dialogVisible.value = true
robotFormAction.value = action robotFormAction.value = action

View File

@ -1,3 +1,7 @@
<!--
* 文件说明代码节点参数面板编辑并校验脚本和输入输出字段
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-collapse v-model="activeNames"> <el-collapse v-model="activeNames">
<el-collapse v-model="activeNames"> <el-collapse v-model="activeNames">
@ -211,6 +215,9 @@ const formData = reactive({
const codeRef = ref() const codeRef = ref()
let editorInstance let editorInstance
/**
* 判断 hasErrors 对应的数据或交互作用范围仅限当前组件或模块
*/
function hasErrors() { function hasErrors() {
const model = editorInstance.getModel(); const model = editorInstance.getModel();
if (!model) return false; if (!model) return false;
@ -220,6 +227,10 @@ function hasErrors() {
// //
return markers.some(marker => marker.severity === monaco.MarkerSeverity.Error); return markers.some(marker => marker.severity === monaco.MarkerSeverity.Error);
} }
/**
* 初始化 initEditor 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} type 目标类型
*/
const initEditor = (type) => { const initEditor = (type) => {
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2020, target: monaco.languages.typescript.ScriptTarget.ES2020,
@ -260,6 +271,10 @@ const initEditor = (type) => {
} }
// //
/**
* 设置 setValue 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} value 待处理的新值
*/
const setValue = (value) => { const setValue = (value) => {
if (editorInstance) { if (editorInstance) {
editorInstance.setValue(value) editorInstance.setValue(value)
@ -267,6 +282,9 @@ const setValue = (value) => {
} }
// //
/**
* 销毁 disposeEditor 对应的数据或交互作用范围仅限当前组件或模块
*/
const disposeEditor = () => { const disposeEditor = () => {
if (editorInstance) { if (editorInstance) {
editorInstance.dispose() editorInstance.dispose()
@ -284,6 +302,11 @@ const activeNames = ref(['1', '2'])
const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id) const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id)
// //
/**
* 新增 addFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
* @param {*} type 目标类型
*/
const addFormItem = (e, type) => { const addFormItem = (e, type) => {
e.stopPropagation() e.stopPropagation()
const obj = { const obj = {
@ -298,11 +321,20 @@ const addFormItem = (e, type) => {
} }
// //
/**
* 处理 handleDelete 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} index 目标项索引
*/
const handleDelete = (index) => { const handleDelete = (index) => {
formData.nodeParams.splice(index, 1) formData.nodeParams.splice(index, 1)
} }
// FormItemRecursive emit // FormItemRecursive emit
/**
* 删除 deleteTopLevelItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} fullPath 字段完整路径
* @param {*} propPath 字段校验路径
*/
const deleteTopLevelItem = (fullPath, propPath) => { const deleteTopLevelItem = (fullPath, propPath) => {
let currentLevel = formData[propPath] let currentLevel = formData[propPath]
for (let i = 0; i < fullPath.length - 1; i++) { for (let i = 0; i < fullPath.length - 1; i++) {
@ -313,6 +345,9 @@ const deleteTopLevelItem = (fullPath, propPath) => {
} }
// //
/**
* 初始化 initData 对应的数据或交互作用范围仅限当前组件或模块
*/
const initData = () => { const initData = () => {
const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || [])) const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || []))
const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || [])) const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || []))
@ -329,6 +364,9 @@ const initData = () => {
} }
// //
/**
* 校验 validateAndSave 对应的数据或交互作用范围仅限当前组件或模块
*/
const validateAndSave = async () => { const validateAndSave = async () => {
const targetObj = formData.nodeParams.find(item => item.name === 'code'); const targetObj = formData.nodeParams.find(item => item.name === 'code');
if (targetObj) { if (targetObj) {
@ -460,4 +498,4 @@ onBeforeUnmount(() => {
height: 300px; height: 300px;
margin: 12px 0; margin: 12px 0;
} }
</style> </style>

View File

@ -1,3 +1,7 @@
<!--
* 文件说明通用设备参数面板选择设备并配置脚本和参数
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-collapse v-model="activeNames"> <el-collapse v-model="activeNames">
<el-collapse v-model="activeNames"> <el-collapse v-model="activeNames">
@ -260,6 +264,9 @@ const formData = reactive({
const codeRef = ref() const codeRef = ref()
let editorInstance let editorInstance
/**
* 判断 hasErrors 对应的数据或交互作用范围仅限当前组件或模块
*/
function hasErrors() { function hasErrors() {
const model = editorInstance.getModel(); const model = editorInstance.getModel();
if (!model) return false; if (!model) return false;
@ -269,6 +276,10 @@ function hasErrors() {
// //
return markers.some(marker => marker.severity === monaco.MarkerSeverity.Error); return markers.some(marker => marker.severity === monaco.MarkerSeverity.Error);
} }
/**
* 初始化 initEditor 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} type 目标类型
*/
const initEditor = (type) => { const initEditor = (type) => {
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2020, target: monaco.languages.typescript.ScriptTarget.ES2020,
@ -309,6 +320,10 @@ const initEditor = (type) => {
} }
// //
/**
* 设置 setValue 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} value 待处理的新值
*/
const setValue = (value) => { const setValue = (value) => {
if (editorInstance) { if (editorInstance) {
editorInstance.setValue(value) editorInstance.setValue(value)
@ -316,6 +331,9 @@ const setValue = (value) => {
} }
// //
/**
* 销毁 disposeEditor 对应的数据或交互作用范围仅限当前组件或模块
*/
const disposeEditor = () => { const disposeEditor = () => {
if (editorInstance) { if (editorInstance) {
editorInstance.dispose() editorInstance.dispose()
@ -341,6 +359,9 @@ const deviceFormRules = {
deviceId: [{ required: true, message: '请选择执行设备', trigger: 'change' }] deviceId: [{ required: true, message: '请选择执行设备', trigger: 'change' }]
} }
/**
* 加载 loadRobotOptions 对应的数据或交互作用范围仅限当前组件或模块
*/
const loadRobotOptions = async () => { const loadRobotOptions = async () => {
robotLoading.value = true robotLoading.value = true
try { try {
@ -354,6 +375,10 @@ const loadRobotOptions = async () => {
} }
} }
/**
* 加载 loadRobotDevices 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} robotId 机器人 ID
*/
const loadRobotDevices = async (robotId) => { const loadRobotDevices = async (robotId) => {
deviceForm.deviceId = '' deviceForm.deviceId = ''
deviceOptions.value = [] deviceOptions.value = []
@ -370,6 +395,9 @@ const loadRobotDevices = async (robotId) => {
} }
} }
/**
* 打开 openDeviceDialog 对应的数据或交互作用范围仅限当前组件或模块
*/
const openDeviceDialog = async () => { const openDeviceDialog = async () => {
deviceDialogVisible.value = true deviceDialogVisible.value = true
deviceForm.robotId = '' deviceForm.robotId = ''
@ -378,6 +406,9 @@ const openDeviceDialog = async () => {
await loadRobotOptions() await loadRobotOptions()
} }
/**
* 确认 confirmDevice 对应的数据或交互作用范围仅限当前组件或模块
*/
const confirmDevice = async () => { const confirmDevice = async () => {
const valid = await deviceFormRef.value?.validate().catch(() => false) const valid = await deviceFormRef.value?.validate().catch(() => false)
if (!valid) return if (!valid) return
@ -397,6 +428,11 @@ const confirmDevice = async () => {
const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id) const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id)
// //
/**
* 新增 addFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
* @param {*} type 目标类型
*/
const addFormItem = (e, type) => { const addFormItem = (e, type) => {
e.stopPropagation() e.stopPropagation()
const obj = { const obj = {
@ -411,11 +447,20 @@ const addFormItem = (e, type) => {
} }
// //
/**
* 处理 handleDelete 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} index 目标项索引
*/
const handleDelete = (index) => { const handleDelete = (index) => {
formData.nodeParams.splice(index, 1) formData.nodeParams.splice(index, 1)
} }
// FormItemRecursive emit // FormItemRecursive emit
/**
* 删除 deleteTopLevelItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} fullPath 字段完整路径
* @param {*} propPath 字段校验路径
*/
const deleteTopLevelItem = (fullPath, propPath) => { const deleteTopLevelItem = (fullPath, propPath) => {
let currentLevel = formData[propPath] let currentLevel = formData[propPath]
for (let i = 0; i < fullPath.length - 1; i++) { for (let i = 0; i < fullPath.length - 1; i++) {
@ -426,6 +471,9 @@ const deleteTopLevelItem = (fullPath, propPath) => {
} }
// //
/**
* 初始化 initData 对应的数据或交互作用范围仅限当前组件或模块
*/
const initData = () => { const initData = () => {
const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || [])) const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || []))
const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || [])) const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || []))
@ -442,6 +490,9 @@ const initData = () => {
} }
// //
/**
* 校验 validateAndSave 对应的数据或交互作用范围仅限当前组件或模块
*/
const validateAndSave = async () => { const validateAndSave = async () => {
const targetObj = formData.nodeParams.find(item => item.name === 'requestJson'); const targetObj = formData.nodeParams.find(item => item.name === 'requestJson');
if (targetObj) { if (targetObj) {

View File

@ -1,3 +1,7 @@
<!--
* 文件说明HTTP 节点参数面板配置请求及输出字段
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-form :inline="true" :model="httpNodeData" :rules="rules" class="http-form" ref="dynamicFormRef" <el-form :inline="true" :model="httpNodeData" :rules="rules" class="http-form" ref="dynamicFormRef"
label-position="top" label-width="auto"> label-position="top" label-width="auto">
@ -352,6 +356,9 @@ const formData = reactive({
const codeRef = ref() const codeRef = ref()
let editorInstance let editorInstance
/**
* 判断 hasErrors 对应的数据或交互作用范围仅限当前组件或模块
*/
function hasErrors() { function hasErrors() {
const model = editorInstance.getModel(); const model = editorInstance.getModel();
if (!model) return false; if (!model) return false;
@ -362,6 +369,10 @@ function hasErrors() {
return markers.some(marker => marker.severity === monaco.MarkerSeverity.Error); return markers.some(marker => marker.severity === monaco.MarkerSeverity.Error);
} }
/**
* 初始化 initEditor 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} type 目标类型
*/
const initEditor = (type) => { const initEditor = (type) => {
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2020, target: monaco.languages.typescript.ScriptTarget.ES2020,
@ -402,6 +413,10 @@ const initEditor = (type) => {
} }
// //
/**
* 设置 setValue 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} value 待处理的新值
*/
const setValue = (value) => { const setValue = (value) => {
if (editorInstance) { if (editorInstance) {
editorInstance.setValue(value) editorInstance.setValue(value)
@ -409,6 +424,9 @@ const setValue = (value) => {
} }
// //
/**
* 销毁 disposeEditor 对应的数据或交互作用范围仅限当前组件或模块
*/
const disposeEditor = () => { const disposeEditor = () => {
if (editorInstance) { if (editorInstance) {
editorInstance.dispose() editorInstance.dispose()
@ -424,6 +442,11 @@ const activeNames = ref(['1', '2', '3', '4'])
const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id) const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id)
// //
/**
* 新增 addFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
* @param {*} type 目标类型
*/
const addFormItem = (e, type) => { const addFormItem = (e, type) => {
e.stopPropagation() e.stopPropagation()
const obj = { const obj = {
@ -438,11 +461,20 @@ const addFormItem = (e, type) => {
} }
// //
/**
* 处理 handleDelete 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} index 目标项索引
*/
const handleDelete = (index) => { const handleDelete = (index) => {
formData.nodeParams.splice(index, 1) formData.nodeParams.splice(index, 1)
} }
// FormItemRecursive emit // FormItemRecursive emit
/**
* 删除 deleteTopLevelItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} fullPath 字段完整路径
* @param {*} propPath 字段校验路径
*/
const deleteTopLevelItem = (fullPath, propPath) => { const deleteTopLevelItem = (fullPath, propPath) => {
let currentLevel = formData[propPath] let currentLevel = formData[propPath]
for (let i = 0; i < fullPath.length - 1; i++) { for (let i = 0; i < fullPath.length - 1; i++) {
@ -461,6 +493,11 @@ const httpNodeData = ref({
} }
}); });
/**
* 新增 addHttpNodeFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
* @param {*} type 目标类型
*/
const addHttpNodeFormItem = (e, type) => { const addHttpNodeFormItem = (e, type) => {
e.stopPropagation(); e.stopPropagation();
if (type === 'body') { if (type === 'body') {
@ -476,6 +513,11 @@ const addHttpNodeFormItem = (e, type) => {
} }
}; };
/**
* 处理 handleHttpNodeDelete 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} type 目标类型
* @param {*} index 目标项索引
*/
const handleHttpNodeDelete = (type, index) => { const handleHttpNodeDelete = (type, index) => {
if (type === 'body') { if (type === 'body') {
httpNodeData.value.body.formData.splice(index, 1); httpNodeData.value.body.formData.splice(index, 1);
@ -485,6 +527,9 @@ const handleHttpNodeDelete = (type, index) => {
}; };
// //
/**
* 初始化 initData 对应的数据或交互作用范围仅限当前组件或模块
*/
const initData = () => { const initData = () => {
const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || [])) const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || []))
const transformedData = transformHttpNodeData(nodeParams); const transformedData = transformHttpNodeData(nodeParams);
@ -503,7 +548,12 @@ const initData = () => {
} }
// //
/**
* 校验 validateAndSave 对应的数据或交互作用范围仅限当前组件或模块
*/
const validateAndSave = async () => { const validateAndSave = async () => {
// JSON
//
let inputValid = true let inputValid = true
if (dynamicFormRef.value) { if (dynamicFormRef.value) {
await dynamicFormRef.value.validate((valid) => { if (!valid) inputValid = false }) await dynamicFormRef.value.validate((valid) => { if (!valid) inputValid = false })
@ -651,4 +701,4 @@ onBeforeUnmount(() => {
height: 300px; height: 300px;
margin: 12px 0; margin: 12px 0;
} }
</style> </style>

View File

@ -1,3 +1,7 @@
<!--
* 文件说明识别节点参数面板配置识别条件和告警规则
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-form :inline="true" :model="RecognizeNodeData" :rules="rules" ref="dynamicFormRef" class="http-form" <el-form :inline="true" :model="RecognizeNodeData" :rules="rules" ref="dynamicFormRef" class="http-form"
label-position="top" label-width="auto"> label-position="top" label-width="auto">
@ -134,6 +138,11 @@ const activeNames = ref(['1', '2'])
const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id) const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id)
// //
/**
* 新增 addFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
* @param {*} type 目标类型
*/
const addFormItem = (e, type) => { const addFormItem = (e, type) => {
e.stopPropagation() e.stopPropagation()
const obj = { const obj = {
@ -159,6 +168,10 @@ const alarmOperators = [
{ label: '不等于NE', value: 'NE' } { label: '不等于NE', value: 'NE' }
] ]
/**
* 新增 addAlarmRule 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const addAlarmRule = (e) => { const addAlarmRule = (e) => {
e.stopPropagation() e.stopPropagation()
RecognizeNodeData.value.alarmRules.push({ RecognizeNodeData.value.alarmRules.push({
@ -169,15 +182,28 @@ const addAlarmRule = (e) => {
}) })
} }
/**
* 删除 deleteAlarmRule 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} index 目标项索引
*/
const deleteAlarmRule = (index) => { const deleteAlarmRule = (index) => {
RecognizeNodeData.value.alarmRules.splice(index, 1) RecognizeNodeData.value.alarmRules.splice(index, 1)
} }
/**
* 新增 addRecognizeItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const addRecognizeItem = (e) => { const addRecognizeItem = (e) => {
e.stopPropagation(); e.stopPropagation();
RecognizeNodeData.value.outputParams.push({ name: "", type: "string", input: "" }); RecognizeNodeData.value.outputParams.push({ name: "", type: "string", input: "" });
} }
/**
* 删除 deleteRecognizeItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} fullPath 字段完整路径
* @param {*} propPath 字段校验路径
*/
const deleteRecognizeItem = (fullPath, propPath) => { const deleteRecognizeItem = (fullPath, propPath) => {
// //
let currentLevel = RecognizeNodeData.value[propPath]; let currentLevel = RecognizeNodeData.value[propPath];
@ -195,6 +221,9 @@ const deleteRecognizeItem = (fullPath, propPath) => {
} }
// //
/**
* 初始化 initData 对应的数据或交互作用范围仅限当前组件或模块
*/
const initData = () => { const initData = () => {
const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || [])) const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || []))
const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || [])) const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || []))
@ -214,6 +243,9 @@ watch(
) )
// //
/**
* 校验 validateAndSave 对应的数据或交互作用范围仅限当前组件或模块
*/
const validateAndSave = async () => { const validateAndSave = async () => {
let inputValid = true let inputValid = true
let outputValid = true let outputValid = true

View File

@ -1,3 +1,7 @@
<!--
* 文件说明智能体参数面板配置智能体调用和语音合成
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-form :inline="true" :model="sdAgentNodeData" :rules="rules" ref="dynamicFormRef" class="http-form" <el-form :inline="true" :model="sdAgentNodeData" :rules="rules" ref="dynamicFormRef" class="http-form"
label-position="top" label-width="auto"> label-position="top" label-width="auto">
@ -162,6 +166,11 @@ const activeNames = ref(['1', '2'])
const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id) const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id)
// //
/**
* 新增 addFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
* @param {*} type 目标类型
*/
const addFormItem = (e, type) => { const addFormItem = (e, type) => {
e.stopPropagation() e.stopPropagation()
const obj = { const obj = {
@ -178,6 +187,9 @@ const addFormItem = (e, type) => {
// //
const sdAgentNodeData = ref({}) const sdAgentNodeData = ref({})
/**
* 处理 voiceOptions 对应的数据或交互作用范围仅限当前组件或模块
*/
const voiceOptions = () => { const voiceOptions = () => {
return [{ return [{
value: 'x4_xiaoyan', value: 'x4_xiaoyan',
@ -185,6 +197,10 @@ const voiceOptions = () => {
}] }]
} }
/**
* 处理 handleTtsChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} val 变更值
*/
const handleTtsChange = (val) => { const handleTtsChange = (val) => {
if (val) { if (val) {
sdAgentNodeData.value.tts = [] sdAgentNodeData.value.tts = []
@ -200,11 +216,20 @@ const handleTtsChange = (val) => {
} }
} }
/**
* 新增 addSdAgentItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const addSdAgentItem = (e) => { const addSdAgentItem = (e) => {
e.stopPropagation(); e.stopPropagation();
sdAgentNodeData.value.outputParams.push({ name: "", type: "string", input: "" }); sdAgentNodeData.value.outputParams.push({ name: "", type: "string", input: "" });
} }
/**
* 删除 deleteSdAgentItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} fullPath 字段完整路径
* @param {*} propPath 字段校验路径
*/
const deleteSdAgentItem = (fullPath, propPath) => { const deleteSdAgentItem = (fullPath, propPath) => {
// //
let currentLevel = sdAgentNodeData.value[propPath]; let currentLevel = sdAgentNodeData.value[propPath];
@ -222,6 +247,9 @@ const deleteSdAgentItem = (fullPath, propPath) => {
} }
// //
/**
* 初始化 initData 对应的数据或交互作用范围仅限当前组件或模块
*/
const initData = () => { const initData = () => {
const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || [])) const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || []))
const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || [])) const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || []))
@ -241,6 +269,9 @@ watch(
) )
// //
/**
* 校验 validateAndSave 对应的数据或交互作用范围仅限当前组件或模块
*/
const validateAndSave = async () => { const validateAndSave = async () => {
let inputValid = true let inputValid = true
let outputValid = true let outputValid = true

View File

@ -1,3 +1,7 @@
<!--
* 文件说明开始节点参数面板配置流程入口参数
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<el-collapse v-model="activeNames"> <el-collapse v-model="activeNames">
<el-collapse-item name="1" icon-position="left"> <el-collapse-item name="1" icon-position="left">
@ -42,6 +46,11 @@ const dynamicFormRef = ref()
const activeNames = ref(['1', '2']) const activeNames = ref(['1', '2'])
// //
/**
* 新增 addFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
* @param {*} type 目标类型
*/
const addFormItem = (e, type) => { const addFormItem = (e, type) => {
e.stopPropagation() e.stopPropagation()
const obj = { const obj = {
@ -56,11 +65,20 @@ const addFormItem = (e, type) => {
} }
// //
/**
* 处理 handleDelete 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} index 目标项索引
*/
const handleDelete = (index) => { const handleDelete = (index) => {
formData.nodeParams.splice(index, 1) formData.nodeParams.splice(index, 1)
} }
// FormItemRecursive emit // FormItemRecursive emit
/**
* 删除 deleteTopLevelItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} fullPath 字段完整路径
* @param {*} propPath 字段校验路径
*/
const deleteTopLevelItem = (fullPath, propPath) => { const deleteTopLevelItem = (fullPath, propPath) => {
let currentLevel = formData[propPath] let currentLevel = formData[propPath]
for (let i = 0; i < fullPath.length - 1; i++) { for (let i = 0; i < fullPath.length - 1; i++) {
@ -71,6 +89,9 @@ const deleteTopLevelItem = (fullPath, propPath) => {
} }
// //
/**
* 初始化 initData 对应的数据或交互作用范围仅限当前组件或模块
*/
const initData = () => { const initData = () => {
const inputParams = JSON.parse(JSON.stringify(props.data.properties.inputParams || [])) const inputParams = JSON.parse(JSON.stringify(props.data.properties.inputParams || []))
formData.inputParams = inputParams; formData.inputParams = inputParams;
@ -85,6 +106,9 @@ watch(
) )
// //
/**
* 校验 validateAndSave 对应的数据或交互作用范围仅限当前组件或模块
*/
const validateAndSave = async () => { const validateAndSave = async () => {
let inputValid = true let inputValid = true
if (dynamicFormRef.value) { if (dynamicFormRef.value) {
@ -180,4 +204,4 @@ defineExpose({ validateAndSave })
cursor: pointer; cursor: pointer;
} }
} }
</style> </style>

View File

@ -1,10 +1,24 @@
/**
* 文件说明参数引用组合逻辑维护可引用字段和级联选择状态
* 作用范围仅服务于流程设计器模块
*/
import { ref } from 'vue' import { ref } from 'vue'
import { getInput } from '@/utils/flow' import { getInput } from '@/utils/flow'
/**
* 处理 useQuote 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} nodeId 流程节点 ID
*/
export function useQuote(nodeId) { export function useQuote(nodeId) {
const quoteOptions = ref([]) const quoteOptions = ref([])
const cascaderRefs = ref([]) const cascaderRefs = ref([])
/**
* 处理 handleTypeChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} index 目标项索引
* @param {*} formData 参数表单数据
* @param {*} type 目标类型
*/
const handleTypeChange = (index, formData, type = 'default') => { const handleTypeChange = (index, formData, type = 'default') => {
// 根据节点类型处理不同数据源 // 根据节点类型处理不同数据源
// 这里简化为通用逻辑,具体实现需根据实际数据结构调整 // 这里简化为通用逻辑,具体实现需根据实际数据结构调整
@ -17,6 +31,13 @@ export function useQuote(nodeId) {
} }
} }
/**
* 处理 cascaderChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} value 待处理的新值
* @param {*} index 目标项索引
* @param {*} formData 参数表单数据
* @param {*} field 调用方传入的 field 参数
*/
const cascaderChange = (value, index, formData, field = 'nodeParams') => { const cascaderChange = (value, index, formData, field = 'nodeParams') => {
const selectedOptions = cascaderRefs.value[index]?.getCheckedNodes(true) const selectedOptions = cascaderRefs.value[index]?.getCheckedNodes(true)
if (selectedOptions && selectedOptions.length) { if (selectedOptions && selectedOptions.length) {
@ -25,6 +46,14 @@ export function useQuote(nodeId) {
} }
} }
/**
* 处理 visibleChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} visible 是否可见
* @param {*} index 目标项索引
* @param {*} currentQuote 调用方传入的 currentQuote 参数
* @param {*} formData 参数表单数据
* @param {*} field 调用方传入的 field 参数
*/
const visibleChange = (visible, index, currentQuote, formData, field = 'nodeParams') => { const visibleChange = (visible, index, currentQuote, formData, field = 'nodeParams') => {
if (visible) { if (visible) {
const option = getInput(nodeId) const option = getInput(nodeId)
@ -50,4 +79,4 @@ export function useQuote(nodeId) {
cascaderChange, cascaderChange,
visibleChange visibleChange
} }
} }

View File

@ -1,9 +1,18 @@
/**
* 文件说明流程事件订阅组合逻辑并在卸载时释放监听器
* 作用范围仅服务于流程设计器模块
*/
import { onUnmounted } from "vue"; import { onUnmounted } from "vue";
import { emitter } from "@/utils/eventBus"; import { emitter } from "@/utils/eventBus";
export const useFlowEvents = () => { export const useFlowEvents = () => {
const listeners = []; const listeners = [];
/**
* 订阅 onFlowEvent 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} type 目标类型
* @param {*} handler 事件处理函数
*/
const onFlowEvent = (type, handler) => { const onFlowEvent = (type, handler) => {
emitter.on(type, handler); emitter.on(type, handler);
listeners.push([type, handler]); listeners.push([type, handler]);

View File

@ -1,3 +1,7 @@
/**
* 文件说明定义流程设计器可用的节点表单字段及下拉选项等静态配置
* 作用范围仅服务于流程设计器模块
*/
import cameraSvg from './icon/camera.svg' import cameraSvg from './icon/camera.svg'
import videoSvg from './icon/video.svg' import videoSvg from './icon/video.svg'
import loopSvg from './icon/loop.svg' import loopSvg from './icon/loop.svg'
@ -12,6 +16,9 @@ import audioSvg from './icon/audio.svg'
import touchSvg from './icon/touch.svg' import touchSvg from './icon/touch.svg'
import expressionSvg from './icon/expression.svg' import expressionSvg from './icon/expression.svg'
/**
* 处理与 http method options 相关的状态或数据该影响范围仅限当前模块
*/
const httpMethodOptions = () => { const httpMethodOptions = () => {
return [{ return [{
value: 'POST', value: 'POST',
@ -28,6 +35,9 @@ const httpMethodOptions = () => {
}] }]
} }
/**
* 处理与 express options 相关的状态或数据该影响范围仅限当前模块
*/
const expressOptions = () => { const expressOptions = () => {
return [{ return [{
value: 1, value: 1,
@ -50,6 +60,9 @@ const expressOptions = () => {
}] }]
} }
/**
* 处理与 task type options 相关的状态或数据该影响范围仅限当前模块
*/
const taskTypeOptions = () => { const taskTypeOptions = () => {
return [{ return [{
value: 'voice', value: 'voice',
@ -60,6 +73,9 @@ const taskTypeOptions = () => {
}] }]
} }
/**
* 处理与 voice options 相关的状态或数据该影响范围仅限当前模块
*/
const voiceOptions = () => { const voiceOptions = () => {
return [{ return [{
value: 'x4_xiaoyan', value: 'x4_xiaoyan',
@ -67,6 +83,9 @@ const voiceOptions = () => {
}] }]
} }
/**
* 处理与 inspection event types 相关的状态或数据该影响范围仅限当前模块
*/
const inspectionEventTypes = () => { const inspectionEventTypes = () => {
return [{ return [{
value: 'No-Glove', value: 'No-Glove',
@ -245,6 +264,10 @@ export const collapseList = [
{ name: "input", type: "input", input: "", required: true }, { name: "input", type: "input", input: "", required: true },
{ name: "code", type: "input", input: ` { name: "code", type: "input", input: `
// 方法定义不能修改 // 方法定义不能修改
/**
* 处理与 r 相关的状态或数据该影响范围仅限当前模块
* @param {*} params 待处理的参数集合
*/
function handler(params) { function handler(params) {
// 返回值是一个可序列化成 json 的 dict 或 object // 返回值是一个可序列化成 json 的 dict 或 object
const result ={ const result ={

View File

@ -1,3 +1,7 @@
<!--
* 文件说明流程设计器主页面负责编辑校验试运行执行跟踪和快捷操作
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="page"> <div class="page">
<el-container class="page__container"> <el-container class="page__container">
@ -314,10 +318,18 @@ const defaultEdgeOptions = {
style: { stroke: "#ff6b35", strokeWidth: 2 }, style: { stroke: "#ff6b35", strokeWidth: 2 },
}; };
/**
* 处理 dragover 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const dragover = (e) => { const dragover = (e) => {
e.preventDefault(); e.preventDefault();
}; };
/**
* 处理 drop 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const drop = (e) => { const drop = (e) => {
let node = e.dataTransfer.getData("flowNode"); let node = e.dataTransfer.getData("flowNode");
if (!node) return; if (!node) return;
@ -349,6 +361,10 @@ const drop = (e) => {
} }
}; };
/**
* 处理 handleConnect 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} connection 连接信息
*/
const handleConnect = (connection) => { const handleConnect = (connection) => {
if (!connection.source || !connection.target) return; if (!connection.source || !connection.target) return;
const edge = lf.addEdge({ const edge = lf.addEdge({
@ -361,6 +377,10 @@ const handleConnect = (connection) => {
lf.emit("edge:add", { data: edge }); lf.emit("edge:add", { data: edge });
}; };
/**
* 处理 handleNodeDoubleClick 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} { node } 调用方传入的 { node } 参数
*/
const handleNodeDoubleClick = ({ node }) => { const handleNodeDoubleClick = ({ node }) => {
const data = lf.getGraphData().nodes.find((item) => item.id === node.id); const data = lf.getGraphData().nodes.find((item) => item.id === node.id);
if (!data || ["selectArea", "branch", "stopLoop", "subStart", "subEnd", "end"].includes(data.type)) return; if (!data || ["selectArea", "branch", "stopLoop", "subStart", "subEnd", "end"].includes(data.type)) return;
@ -368,6 +388,10 @@ const handleNodeDoubleClick = ({ node }) => {
paramsDrawerData.value = data; paramsDrawerData.value = data;
}; };
/**
* 查找 findLoopAtPoint 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} point 画布坐标
*/
const findLoopAtPoint = (point) => { const findLoopAtPoint = (point) => {
return (vueFlow.getNodes.value || []).find((candidate) => { return (vueFlow.getNodes.value || []).find((candidate) => {
if (candidate.data?.flowType !== "loop") return false; if (candidate.data?.flowType !== "loop") return false;
@ -381,6 +405,10 @@ const findLoopAtPoint = (point) => {
}); });
}; };
/**
* 查找 findContainingLoop 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} node 当前流程节点
*/
const findContainingLoop = (node) => { const findContainingLoop = (node) => {
const position = node.computedPosition || node.position; const position = node.computedPosition || node.position;
const width = Number(node.dimensions?.width || node.data?.size?.width || 0); const width = Number(node.dimensions?.width || node.data?.size?.width || 0);
@ -388,12 +416,21 @@ const findContainingLoop = (node) => {
return findLoopAtPoint({ x: position.x + width / 2, y: position.y + height / 2 }); return findLoopAtPoint({ x: position.x + width / 2, y: position.y + height / 2 });
}; };
/**
* 处理 eventClientPoint 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} event 触发操作的浏览器事件
*/
const eventClientPoint = (event) => { const eventClientPoint = (event) => {
const pointer = event?.touches?.[0] || event?.changedTouches?.[0] || event; const pointer = event?.touches?.[0] || event?.changedTouches?.[0] || event;
if (!Number.isFinite(pointer?.clientX) || !Number.isFinite(pointer?.clientY)) return null; if (!Number.isFinite(pointer?.clientX) || !Number.isFinite(pointer?.clientY)) return null;
return { x: pointer.clientX, y: pointer.clientY }; return { x: pointer.clientX, y: pointer.clientY };
}; };
/**
* 处理 handleNodeDragStart 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} { node 调用方传入的 { node 参数
* @param {*} event } 调用方传入的 event } 参数
*/
const handleNodeDragStart = ({ node, event }) => { const handleNodeDragStart = ({ node, event }) => {
const drag = lf.prepareLoopChildDrag(node.id); const drag = lf.prepareLoopChildDrag(node.id);
const clientPoint = eventClientPoint(event); const clientPoint = eventClientPoint(event);
@ -405,6 +442,11 @@ const handleNodeDragStart = ({ node, event }) => {
}); });
}; };
/**
* 更新 updateLoopChildDrag 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} { node 调用方传入的 { node 参数
* @param {*} event } 调用方传入的 event } 参数
*/
const updateLoopChildDrag = ({ node, event }) => { const updateLoopChildDrag = ({ node, event }) => {
const drag = loopChildDragContexts.get(node.id); const drag = loopChildDragContexts.get(node.id);
const clientPoint = eventClientPoint(event); const clientPoint = eventClientPoint(event);
@ -416,8 +458,16 @@ const updateLoopChildDrag = ({ node, event }) => {
}); });
}; };
/**
* 处理 handleNodeDrag 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} payload 事件数据
*/
const handleNodeDrag = (payload) => updateLoopChildDrag(payload); const handleNodeDrag = (payload) => updateLoopChildDrag(payload);
/**
* 处理 handleNodeDragStop 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} payload 事件数据
*/
const handleNodeDragStop = (payload) => { const handleNodeDragStop = (payload) => {
const { node } = payload; const { node } = payload;
updateLoopChildDrag(payload); updateLoopChildDrag(payload);
@ -435,21 +485,37 @@ const handleNodeDragStop = (payload) => {
lf.markChanged(); lf.markChanged();
}; };
/**
* 处理 handleNodesChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} changes 变更集合
*/
const handleNodesChange = (changes) => { const handleNodesChange = (changes) => {
if (changes.some((change) => ["add", "remove"].includes(change.type) || (change.type === "position" && change.dragging === false))) { if (changes.some((change) => ["add", "remove"].includes(change.type) || (change.type === "position" && change.dragging === false))) {
lf.markChanged(); lf.markChanged();
} }
}; };
/**
* 处理 handleEdgesChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} changes 变更集合
*/
const handleEdgesChange = (changes) => { const handleEdgesChange = (changes) => {
if (changes.some((change) => ["add", "remove"].includes(change.type))) lf.markChanged(); if (changes.some((change) => ["add", "remove"].includes(change.type))) lf.markChanged();
}; };
/**
* 处理 handleEdgeClick 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} { event 调用方传入的 { event 参数
* @param {*} edge } 调用方传入的 edge } 参数
*/
const handleEdgeClick = ({ event, edge }) => { const handleEdgeClick = ({ event, edge }) => {
event?.stopPropagation?.(); event?.stopPropagation?.();
lf.selectElementById(edge.id); lf.selectElementById(edge.id);
}; };
/**
* 处理 handlePaneClick 对应的数据或交互作用范围仅限当前组件或模块
*/
const handlePaneClick = () => lf.clearSelectElements(); const handlePaneClick = () => lf.clearSelectElements();
const flowStore = useFlowStore(); const flowStore = useFlowStore();
@ -507,6 +573,9 @@ const testRun = async () => {
}; };
// //
/**
* 处理 flowPauseFn 对应的数据或交互作用范围仅限当前组件或模块
*/
const flowPauseFn = async () => { const flowPauseFn = async () => {
const res = await flowPause(instId.value); const res = await flowPause(instId.value);
if (res.code === 200) { if (res.code === 200) {
@ -520,6 +589,9 @@ const hasRunResult = ref(false);
let flowPollTimer = null; let flowPollTimer = null;
let flowDisposed = false; let flowDisposed = false;
/**
* 清理 clearFlowPollTimer 对应的数据或交互作用范围仅限当前组件或模块
*/
const clearFlowPollTimer = () => { const clearFlowPollTimer = () => {
if (flowPollTimer !== null) { if (flowPollTimer !== null) {
window.clearTimeout(flowPollTimer); window.clearTimeout(flowPollTimer);
@ -527,6 +599,12 @@ const clearFlowPollTimer = () => {
} }
}; };
/**
* 调度 scheduleFlowView 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} currentInstId 当前流程实例 ID
* @param {*} taskId 任务 ID
* @param {*} delay 延迟毫秒数
*/
const scheduleFlowView = (currentInstId, taskId = null, delay = 2000) => { const scheduleFlowView = (currentInstId, taskId = null, delay = 2000) => {
clearFlowPollTimer(); clearFlowPollTimer();
flowPollTimer = window.setTimeout(() => { flowPollTimer = window.setTimeout(() => {
@ -535,6 +613,9 @@ const scheduleFlowView = (currentInstId, taskId = null, delay = 2000) => {
}, delay); }, delay);
}; };
/**
* 处理 flowResumeFn 对应的数据或交互作用范围仅限当前组件或模块
*/
const flowResumeFn = async () => { const flowResumeFn = async () => {
const res = await flowResume(instId.value); const res = await flowResume(instId.value);
if (res.code === 200) { if (res.code === 200) {
@ -545,6 +626,9 @@ const flowResumeFn = async () => {
} }
}; };
/**
* 处理 flowStopFn 对应的数据或交互作用范围仅限当前组件或模块
*/
const flowStopFn = async () => { const flowStopFn = async () => {
const res = await flowStop(instId.value); const res = await flowStop(instId.value);
if (res.code === 200) { if (res.code === 200) {
@ -593,6 +677,8 @@ const hasSameEdge = (edge, ignoredId) => lf.getGraphData().edges.some((item) =>
)); ));
const validEdge = (data) => { const validEdge = (data) => {
// 线
// 线
const sourceModel = lf.getNodeModelById(data.sourceNodeId); const sourceModel = lf.getNodeModelById(data.sourceNodeId);
const targetModel = lf.getNodeModelById(data.targetNodeId); const targetModel = lf.getNodeModelById(data.targetNodeId);
if (!sourceModel || !targetModel) { if (!sourceModel || !targetModel) {
@ -664,6 +750,8 @@ const changeState = (value) => {
}; };
const loopFlowView = async (instId, taskId = null) => { const loopFlowView = async (instId, taskId = null) => {
// 使 ID
//
const params = { const params = {
itemId: flowInfoData.value.itemId, itemId: flowInfoData.value.itemId,
instId, instId,
@ -1009,6 +1097,10 @@ const handleSingleNodeRobotChange = async (robotId) => {
} }
}; };
/**
* 处理 stationOptions 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} stations 站点集合
*/
const stationOptions = (stations) => (Array.isArray(stations) ? stations : []) const stationOptions = (stations) => (Array.isArray(stations) ? stations : [])
.filter((station) => station?.id !== undefined && station?.id !== null && String(station.id).trim()) .filter((station) => station?.id !== undefined && station?.id !== null && String(station.id).trim())
.map((station) => { .map((station) => {
@ -1017,6 +1109,9 @@ const stationOptions = (stations) => (Array.isArray(stations) ? stations : [])
return { value: id, label: description ? `${id} - ${description}` : id }; return { value: id, label: description ? `${id} - ${description}` : id };
}); });
/**
* 加载 loadSingleNodeStations 对应的数据或交互作用范围仅限当前组件或模块
*/
const loadSingleNodeStations = async () => { const loadSingleNodeStations = async () => {
stationLoading.value = true; stationLoading.value = true;
try { try {
@ -1040,6 +1135,9 @@ const loadSingleNodeStations = async () => {
} }
}; };
/**
* 加载 loadSingleNodeRobots 对应的数据或交互作用范围仅限当前组件或模块
*/
const loadSingleNodeRobots = async () => { const loadSingleNodeRobots = async () => {
const response = await getRobotList({ pageNum: 1, pageSize: 1000, connectStatus: '1' }); const response = await getRobotList({ pageNum: 1, pageSize: 1000, connectStatus: '1' });
singleNodeRobotOptions.value = (response.rows || []).map(item => ({ singleNodeRobotOptions.value = (response.rows || []).map(item => ({
@ -1048,6 +1146,10 @@ const loadSingleNodeRobots = async () => {
})); }));
}; };
/**
* 处理 singleNodeExecution 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const singleNodeExecution = async (e) => { const singleNodeExecution = async (e) => {
rememberSingleNodeRobot(); rememberSingleNodeRobot();
const { name, nodeType, nodeParams, action, nodeId } = e.detail; const { name, nodeType, nodeParams, action, nodeId } = e.detail;
@ -1090,6 +1192,9 @@ const singleNodeExecution = async (e) => {
} }
}; };
/**
* 执行 execute 对应的数据或交互作用范围仅限当前组件或模块
*/
const execute = async () => { const execute = async () => {
if (nodeAction.value === "AGV_MOVE_TO_STATION") { if (nodeAction.value === "AGV_MOVE_TO_STATION") {
const stationParam = formData.nodeParams.find((item) => item.name === "stationId"); const stationParam = formData.nodeParams.find((item) => item.name === "stationId");
@ -1124,6 +1229,9 @@ const execute = async () => {
const showParamsDrawer = ref(false); const showParamsDrawer = ref(false);
const paramsDrawerData = ref({}); const paramsDrawerData = ref({});
/**
* 清理 clearRun 对应的数据或交互作用范围仅限当前组件或模块
*/
const clearRun = () => { const clearRun = () => {
const { nodes } = lf.getGraphData(); const { nodes } = lf.getGraphData();
nodes.forEach((item) => { nodes.forEach((item) => {
@ -1155,10 +1263,18 @@ const EDITABLE_SELECTOR = [
"[role='dialog']", "[role='dialog']",
].join(","); ].join(",");
/**
* 判断 isEditableElement 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} element 调用方传入的 element 参数
*/
const isEditableElement = (element) => ( const isEditableElement = (element) => (
element instanceof Element && Boolean(element.closest(EDITABLE_SELECTOR)) element instanceof Element && Boolean(element.closest(EDITABLE_SELECTOR))
); );
/**
* 判断 isTextEditing 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} event 触发操作的浏览器事件
*/
const isTextEditing = (event) => { const isTextEditing = (event) => {
const eventPath = typeof event.composedPath === "function" ? event.composedPath() : []; const eventPath = typeof event.composedPath === "function" ? event.composedPath() : [];
if (eventPath.some(isEditableElement)) return true; if (eventPath.some(isEditableElement)) return true;
@ -1166,13 +1282,23 @@ const isTextEditing = (event) => {
return Boolean(window.getSelection()?.toString()); return Boolean(window.getSelection()?.toString());
}; };
/**
* 复制 copySelectedNodes 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} event 触发操作的浏览器事件
*/
const copySelectedNodes = (event) => { const copySelectedNodes = (event) => {
// 线
// ID
const selectedNodes = lf.getSelectElements().nodes; const selectedNodes = lf.getSelectElements().nodes;
if (!selectedNodes.length) return; if (!selectedNodes.length) return;
const graph = lf.getGraphData(); const graph = lf.getGraphData();
const nodeById = new Map(graph.nodes.map((node) => [node.id, node])); const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
const selectedIds = new Set(selectedNodes.map((node) => node.id)); const selectedIds = new Set(selectedNodes.map((node) => node.id));
/**
* 新增 addChildren 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} nodeId 流程节点 ID
*/
const addChildren = (nodeId) => { const addChildren = (nodeId) => {
const node = nodeById.get(nodeId); const node = nodeById.get(nodeId);
(node?.children || []).forEach((childId) => { (node?.children || []).forEach((childId) => {
@ -1200,11 +1326,23 @@ const copySelectedNodes = (event) => {
pasteCount = 0; pasteCount = 0;
}; };
/**
* 重映射 remapNodeAnchorId 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} anchorId 锚点 ID
* @param {*} oldNodeId 原节点 ID
* @param {*} newNodeId 新节点 ID
*/
const remapNodeAnchorId = (anchorId, oldNodeId, newNodeId) => { const remapNodeAnchorId = (anchorId, oldNodeId, newNodeId) => {
if (!anchorId || !String(anchorId).startsWith(`${oldNodeId}_`)) return anchorId; if (!anchorId || !String(anchorId).startsWith(`${oldNodeId}_`)) return anchorId;
return `${newNodeId}${String(anchorId).slice(oldNodeId.length)}`; return `${newNodeId}${String(anchorId).slice(oldNodeId.length)}`;
}; };
/**
* 重映射 remapCopiedNodeReferences 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} value 待处理的新值
* @param {*} idMap 节点 ID 映射
* @param {*} parentKey 递归父键名
*/
const remapCopiedNodeReferences = (value, idMap, parentKey = "") => { const remapCopiedNodeReferences = (value, idMap, parentKey = "") => {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const result = value.map((item) => remapCopiedNodeReferences(item, idMap)); const result = value.map((item) => remapCopiedNodeReferences(item, idMap));
@ -1219,7 +1357,13 @@ const remapCopiedNodeReferences = (value, idMap, parentKey = "") => {
))); )));
}; };
/**
* 粘贴 pasteCopiedNodes 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} event 触发操作的浏览器事件
*/
const pasteCopiedNodes = (event) => { const pasteCopiedNodes = (event) => {
// ID ID 线
// ID
if (!copiedGraph.nodes.length || flowStore.disableForm) return; if (!copiedGraph.nodes.length || flowStore.disableForm) return;
event.preventDefault(); event.preventDefault();
@ -1297,6 +1441,10 @@ const pasteCopiedNodes = (event) => {
}); });
}; };
/**
* 处理 handleKeyboardShortcut 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} event 触发操作的浏览器事件
*/
const handleKeyboardShortcut = (event) => { const handleKeyboardShortcut = (event) => {
if (isTextEditing(event)) return; if (isTextEditing(event)) return;

View File

@ -1,3 +1,7 @@
<!--
* 文件说明流程正常结束节点
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container"> <div class="node__container">
<div class="terminal-node"> <div class="terminal-node">

View File

@ -1,3 +1,7 @@
<!--
* 文件说明节点分组容器并展示成员数量
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="group__container"> <div class="group__container">
<NodeTitle <NodeTitle
@ -33,6 +37,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { ...properties, name }); lf.setProperties(props.model.id, { ...properties, name });

View File

@ -1,3 +1,7 @@
<!--
* 文件说明通用服务节点并响应运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -63,6 +67,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -80,6 +88,9 @@ const errorInfoData = ref('');
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明流程入口节点并响应运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<keep-alive> <keep-alive>
@ -42,6 +46,9 @@ const outputJsonData = ref({});
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明代码执行节点并展示运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -61,6 +65,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -78,6 +86,9 @@ const errorInfoData = ref('');
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明当前循环上下文节点并展示运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -47,6 +51,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -63,6 +71,9 @@ const outputJsonData = ref({});
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明通用设备执行节点并展示运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -61,6 +65,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -78,6 +86,9 @@ const errorInfoData = ref('');
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明HTTP 请求执行节点并展示运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -62,6 +66,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -79,6 +87,9 @@ const errorInfoData = ref('');
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明循环容器节点管理循环体节点拖入和布局
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div <div
class="group__container" class="group__container"
@ -46,15 +50,27 @@ const emits = defineEmits(["bindRef", "addToGroup", "contentChange"]);
const isDragOver = ref(false); const isDragOver = ref(false);
const actualChildCount = computed(() => props.childCount ?? props.model?.children?.size ?? 0); const actualChildCount = computed(() => props.childCount ?? props.model?.children?.size ?? 0);
/**
* 处理 handleDragover 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const handleDragover = (e) => { const handleDragover = (e) => {
e.preventDefault(); e.preventDefault();
isDragOver.value = true; isDragOver.value = true;
}; };
/**
* 处理 handleDragleave 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const handleDragleave = (e) => { const handleDragleave = (e) => {
if (!e.currentTarget.contains(e.relatedTarget)) isDragOver.value = false; if (!e.currentTarget.contains(e.relatedTarget)) isDragOver.value = false;
}; };
/**
* 处理 handleDrop 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const handleDrop = (e) => { const handleDrop = (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -84,6 +100,10 @@ const handleDrop = (e) => {
lf.addToGroup(props.model.id, node.id, point.canvasOverlayPosition); lf.addToGroup(props.model.id, node.id, point.canvasOverlayPosition);
}; };
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {

View File

@ -1,3 +1,7 @@
<!--
* 文件说明识别执行节点并展示运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -48,6 +52,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -64,6 +72,9 @@ const outputJsonData = ref({});
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明智能体执行节点并展示运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -48,6 +52,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -64,6 +72,9 @@ const outputJsonData = ref({});
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明延时等待节点并展示运行状态
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" :class="props.model.id"> <div class="node__container" :class="props.model.id">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -47,6 +51,10 @@ const props = defineProps({
const emits = defineEmits(["contentChange"]); const emits = defineEmits(["contentChange"]);
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -63,6 +71,9 @@ const outputJsonData = ref({});
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明终止循环节点用于结束当前循环
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" > <div class="node__container" >
<!-- 状态栏 --> <!-- 状态栏 -->
@ -16,6 +20,10 @@ const props = defineProps({
text: String, text: String,
}); });
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -194,4 +202,4 @@ const setNodeName = (name) => {
} }
} }
} }
</style> </style>

View File

@ -1,3 +1,7 @@
<!--
* 文件说明循环体单次执行出口节点
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container"> <div class="node__container">
<div class="terminal-node"> <div class="terminal-node">

View File

@ -1,3 +1,7 @@
<!--
* 文件说明循环体单次执行入口节点
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container"> <div class="node__container">
<div class="terminal-node"> <div class="terminal-node">

View File

@ -1,3 +1,7 @@
<!--
* 文件说明条件分支节点配置条件组和动态分支锚点
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div class="node__container" ref="switchRef" @mouseleave="setNodeProperties"> <div class="node__container" ref="switchRef" @mouseleave="setNodeProperties">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
@ -299,10 +303,18 @@ const formData = reactive({
nodeParams: props.properties?.conditions || [], nodeParams: props.properties?.conditions || [],
}); });
/**
* 新增 addFormItem 对应的数据或交互作用范围仅限当前组件或模块
*/
const addFormItem = () => { const addFormItem = () => {
addCondition(0); addCondition(0);
}; };
/**
* 删除 deleteFormItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} id 目标元素 ID
* @param {*} index 目标项索引
*/
const deleteFormItem = (id, index) => { const deleteFormItem = (id, index) => {
if (index === 0) { if (index === 0) {
return; return;
@ -316,6 +328,11 @@ const deleteFormItem = (id, index) => {
}; };
const quoteOptions = ref([]); const quoteOptions = ref([]);
/**
* 处理 handleTypeChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} pIndex 条件组索引
* @param {*} index 目标项索引
*/
const handleTypeChange = (pIndex, index) => { const handleTypeChange = (pIndex, index) => {
if (formData.nodeParams[pIndex].list[index].type === "input") { if (formData.nodeParams[pIndex].list[index].type === "input") {
formData.nodeParams[pIndex].list[index].quote = ""; formData.nodeParams[pIndex].list[index].quote = "";
@ -328,6 +345,10 @@ const handleTypeChange = (pIndex, index) => {
} }
}; };
/**
* 新增 addCondition 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} height 锚点纵向位置
*/
const addCondition = (height) => { const addCondition = (height) => {
const id = randomUUID().replace(/-/g, ""); const id = randomUUID().replace(/-/g, "");
formData.nodeParams.push({ formData.nodeParams.push({
@ -351,6 +372,11 @@ const addCondition = (height) => {
}); });
}; };
/**
* 新增 addListItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} pIndex 条件组索引
* @param {*} cIndex 条件项索引
*/
const addListItem = (pIndex, cIndex) => { const addListItem = (pIndex, cIndex) => {
formData.nodeParams[pIndex].list.push({ formData.nodeParams[pIndex].list.push({
name: "", name: "",
@ -365,6 +391,11 @@ const addListItem = (pIndex, cIndex) => {
}); });
}; };
/**
* 移除 removeListItem 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} pIndex 条件组索引
* @param {*} cIndex 条件项索引
*/
const removeListItem = (pIndex, cIndex) => { const removeListItem = (pIndex, cIndex) => {
if (cIndex === 0) { if (cIndex === 0) {
return; return;
@ -378,7 +409,12 @@ const removeListItem = (pIndex, cIndex) => {
let anchorSyncFrame = null; let anchorSyncFrame = null;
let resizeObserver = null; let resizeObserver = null;
/**
* 同步 syncAnchorPositions 对应的数据或交互作用范围仅限当前组件或模块
*/
const syncAnchorPositions = () => { const syncAnchorPositions = () => {
//
//
const root = switchRef.value; const root = switchRef.value;
if (!root) return; if (!root) return;
const rootRect = root.getBoundingClientRect(); const rootRect = root.getBoundingClientRect();
@ -393,6 +429,9 @@ const syncAnchorPositions = () => {
emits("syncAnchors", positions); emits("syncAnchors", positions);
}; };
/**
* 调度 scheduleAnchorSync 对应的数据或交互作用范围仅限当前组件或模块
*/
const scheduleAnchorSync = () => { const scheduleAnchorSync = () => {
if (anchorSyncFrame !== null) cancelAnimationFrame(anchorSyncFrame); if (anchorSyncFrame !== null) cancelAnimationFrame(anchorSyncFrame);
anchorSyncFrame = requestAnimationFrame(() => { anchorSyncFrame = requestAnimationFrame(() => {
@ -401,6 +440,9 @@ const scheduleAnchorSync = () => {
}); });
}; };
/**
* 设置 setNodeProperties 对应的数据或交互作用范围仅限当前组件或模块
*/
const setNodeProperties = async () => { const setNodeProperties = async () => {
try { try {
const valid = await dynamicForm.value.validate(); const valid = await dynamicForm.value.validate();
@ -418,6 +460,10 @@ const setNodeProperties = async () => {
} }
}; };
/**
* 设置 setNodeName 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} name 名称或事件名称
*/
const setNodeName = (name) => { const setNodeName = (name) => {
const properties = lf.getProperties(props.model.id); const properties = lf.getProperties(props.model.id);
lf.setProperties(props.model.id, { lf.setProperties(props.model.id, {
@ -427,6 +473,13 @@ const setNodeName = (name) => {
emits("contentChange"); emits("contentChange");
} }
/**
* 处理 visibleChange 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} value 待处理的新值
* @param {*} type 目标类型
* @param {*} index 目标项索引
* @param {*} pIndex 条件组索引
*/
const visibleChange = async (value, type, index, pIndex) => { const visibleChange = async (value, type, index, pIndex) => {
if (value) { if (value) {
const option = getInput(props.model.id); const option = getInput(props.model.id);
@ -468,6 +521,9 @@ watch(
const nodeStateRef = ref(null); const nodeStateRef = ref(null);
/**
* 关闭 closePopover 对应的数据或交互作用范围仅限当前组件或模块
*/
const closePopover = () => { const closePopover = () => {
if (nodeStateRef.value) { if (nodeStateRef.value) {
nodeStateRef.value.closePopover(); nodeStateRef.value.closePopover();
@ -475,6 +531,10 @@ const closePopover = () => {
} }
const isEditing = ref(false) const isEditing = ref(false)
/**
* 处理 handleInputFocus 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const handleInputFocus = (e) => { const handleInputFocus = (e) => {
// //
e.stopPropagation() e.stopPropagation()
@ -482,6 +542,10 @@ const handleInputFocus = (e) => {
} }
/**
* 处理 handleInputKeydown 对应的数据或交互作用范围仅限当前组件或模块
* @param {*} e 触发操作的浏览器事件
*/
const handleInputKeydown = (e) => { const handleInputKeydown = (e) => {
// //
e.stopPropagation(); e.stopPropagation();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明Vue Flow 连线渲染组件负责路径展示及选中状态下的删除操作
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<BaseEdge <BaseEdge
:id="id" :id="id"
@ -54,6 +58,9 @@ const deleteActionStyle = computed(() => ({
transform: `translate(-50%, -50%) translate(${pathData.value[1]}px, ${pathData.value[2]}px)`, transform: `translate(-50%, -50%) translate(${pathData.value[1]}px, ${pathData.value[2]}px)`,
})); }));
/**
* 删除与 edge 相关的状态或数据该影响范围仅限当前组件
*/
const deleteEdge = () => { const deleteEdge = () => {
window.lf?.deleteEdge(props.id); window.lf?.deleteEdge(props.id);
window.lf?.clearSelectElements(); window.lf?.clearSelectElements();

View File

@ -1,3 +1,7 @@
<!--
* 文件说明Vue Flow 节点壳组件负责锚点连接规则分支位置及分组交互适配
* 作用范围仅服务于流程设计器模块
-->
<template> <template>
<div <div
class="flow-node-shell" class="flow-node-shell"
@ -130,22 +134,39 @@ const branchAnchors = computed(() => {
}); });
const model = computed(() => window.lf?.getNodeModelById(props.id)); const model = computed(() => window.lf?.getNodeModelById(props.id));
/**
* 获取与 loop scope 相关的状态或数据该影响范围仅限当前组件
* @param {*} nodeId 流程节点 ID
*/
const getLoopScope = (nodeId) => { const getLoopScope = (nodeId) => {
const node = vueFlow.findNode(nodeId); const node = vueFlow.findNode(nodeId);
const parent = node?.parentNode ? vueFlow.findNode(node.parentNode) : null; const parent = node?.parentNode ? vueFlow.findNode(node.parentNode) : null;
return parent?.data?.flowType === "loop" ? parent.id : null; return parent?.data?.flowType === "loop" ? parent.id : null;
}; };
/**
* 判断与 valid loop connection 相关的状态或数据该影响范围仅限当前组件
* @param {*} connection 待校验或创建的连接信息
*/
const isValidLoopConnection = (connection) => { const isValidLoopConnection = (connection) => {
if (!connection.source || !connection.target || connection.source === connection.target) return false; if (!connection.source || !connection.target || connection.source === connection.target) return false;
return getLoopScope(connection.source) === getLoopScope(connection.target); return getLoopScope(connection.source) === getLoopScope(connection.target);
}; };
/**
* 同步与 anchors 相关的状态或数据该影响范围仅限当前组件
* @param {*} anchors 需要同步的锚点集合
*/
const syncAnchors = (anchors) => { const syncAnchors = (anchors) => {
window.lf?.setProperties(props.id, { ...window.lf.getProperties(props.id), anchor: anchors }); window.lf?.setProperties(props.id, { ...window.lf.getProperties(props.id), anchor: anchors });
vueFlow.updateNodeInternals([props.id]); vueFlow.updateNodeInternals([props.id]);
}; };
/**
* 新增与 anchor 相关的状态或数据该影响范围仅限当前组件
* @param {*} height 锚点纵向位置
* @param {*} anchorId 分支锚点 ID
*/
const addAnchor = (height, anchorId) => { const addAnchor = (height, anchorId) => {
const anchors = [...branchAnchors.value]; const anchors = [...branchAnchors.value];
if (!anchors.some((anchor) => anchor.id === anchorId)) { if (!anchors.some((anchor) => anchor.id === anchorId)) {
@ -154,8 +175,21 @@ const addAnchor = (height, anchorId) => {
} }
}; };
/**
* 移除与 anchor 相关的状态或数据该影响范围仅限当前组件
* @param {*} anchorId 分支锚点 ID
*/
const removeAnchor = (anchorId) => syncAnchors(branchAnchors.value.filter((anchor) => anchor.id !== anchorId)); const removeAnchor = (anchorId) => syncAnchors(branchAnchors.value.filter((anchor) => anchor.id !== anchorId));
/**
* 更新与 anchor 相关的状态或数据该影响范围仅限当前组件
* @param {*} height 锚点纵向位置
* @param {*} anchorId 分支锚点 ID
*/
const changeAnchor = (height, anchorId) => syncAnchors(branchAnchors.value.map((anchor) => anchor.id === anchorId ? { ...anchor, height } : anchor)); const changeAnchor = (height, anchorId) => syncAnchors(branchAnchors.value.map((anchor) => anchor.id === anchorId ? { ...anchor, height } : anchor));
/**
* 同步与 branch anchors 相关的状态或数据该影响范围仅限当前组件
* @param {*} positions 分支锚点位置集合
*/
const syncBranchAnchors = (positions = []) => { const syncBranchAnchors = (positions = []) => {
if (!positions.length) return; if (!positions.length) return;
const positionMap = new Map(positions.map((item) => [item.id, Number(item.height || 0)])); const positionMap = new Map(positions.map((item) => [item.id, Number(item.height || 0)]));
@ -176,11 +210,23 @@ const syncBranchAnchors = (positions = []) => {
if (changed) syncAnchors(anchors); if (changed) syncAnchors(anchors);
else vueFlow.updateNodeInternals([props.id]); else vueFlow.updateNodeInternals([props.id]);
}; };
/**
* 处理与 content changed 相关的状态或数据该影响范围仅限当前组件
*/
const contentChanged = () => { const contentChanged = () => {
vueFlow.updateNodeInternals([props.id]); vueFlow.updateNodeInternals([props.id]);
window.lf?.markChanged(); window.lf?.markChanged();
}; };
/**
* 绑定与 component 相关的状态或数据该影响范围仅限当前组件
* @param {*} instance 节点组件实例
*/
const bindComponent = (instance) => window.lf?.registerComponentInstance(props.id, instance); const bindComponent = (instance) => window.lf?.registerComponentInstance(props.id, instance);
/**
* 新增与 to group 相关的状态或数据该影响范围仅限当前组件
* @param {*} childId 子节点 ID
* @param {*} dropCenter 拖放中心点坐标
*/
const addToGroup = (childId, dropCenter) => window.lf?.addToGroup(props.id, childId, dropCenter); const addToGroup = (childId, dropCenter) => window.lf?.addToGroup(props.id, childId, dropCenter);
onMounted(() => bindComponent(componentRef.value)); onMounted(() => bindComponent(componentRef.value));

View File

@ -1,7 +1,15 @@
/**
* 文件说明旧流程数据与 Vue Flow 状态操作 API 之间的兼容适配层
* 作用范围仅服务于流程设计器模块
*/
import { nextTick } from "vue"; import { nextTick } from "vue";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { MarkerType } from "@vue-flow/core"; import { MarkerType } from "@vue-flow/core";
/**
* 克隆 clone 对应的数据或交互作用范围仅限画布适配层
* @param {*} value 待处理的新值
*/
const clone = (value) => JSON.parse(JSON.stringify(value ?? {})); const clone = (value) => JSON.parse(JSON.stringify(value ?? {}));
const GROUP_TYPES = new Set(["loop", "selectArea"]); const GROUP_TYPES = new Set(["loop", "selectArea"]);
@ -11,6 +19,9 @@ const LOOP_BODY_INSET = { left: 24, top: 112, right: 24, bottom: 24 };
const GROUP_BODY_INSET = { left: 24, top: 120, right: 24, bottom: 24 }; const GROUP_BODY_INSET = { left: 24, top: 120, right: 24, bottom: 24 };
const LOOP_MIN_SIZE = { width: 520, height: 360 }; const LOOP_MIN_SIZE = { width: 520, height: 360 };
/**
* 处理 loopChildExtent 对应的数据或交互作用范围仅限画布适配层
*/
const loopChildExtent = () => ({ const loopChildExtent = () => ({
range: "parent", range: "parent",
padding: [ padding: [
@ -21,6 +32,9 @@ const loopChildExtent = () => ({
], ],
}); });
/**
* 编组 groupChildExtent 对应的数据或交互作用范围仅限画布适配层
*/
const groupChildExtent = () => ({ const groupChildExtent = () => ({
range: "parent", range: "parent",
padding: [ padding: [
@ -31,6 +45,10 @@ const groupChildExtent = () => ({
], ],
}); });
/**
* 处理 nodeSize 对应的数据或交互作用范围仅限画布适配层
* @param {*} node 当前流程节点
*/
const nodeSize = (node) => { const nodeSize = (node) => {
const width = Number(node.properties?.width || node.width); const width = Number(node.properties?.width || node.width);
const height = Number(node.properties?.height || node.height); const height = Number(node.properties?.height || node.height);
@ -45,9 +63,21 @@ const nodeSize = (node) => {
return { width: 372, height: 180 }; return { width: 372, height: 180 };
}; };
/**
* 处理 edgeId 对应的数据或交互作用范围仅限画布适配层
*/
const edgeId = () => `edge_${uuid().replace(/-/g, "")}`; const edgeId = () => `edge_${uuid().replace(/-/g, "")}`;
/**
* 处理 nodeId 对应的数据或交互作用范围仅限画布适配层
*/
const nodeId = () => uuid().replace(/-/g, ""); const nodeId = () => uuid().replace(/-/g, "");
/**
* 处理 toVueNode 对应的数据或交互作用范围仅限画布适配层
* @param {*} node 当前流程节点
* @param {*} sizeOverride 调用方传入的 sizeOverride 参数
* @param {*} positionOverride 调用方传入的 positionOverride 参数
*/
const toVueNode = (node, sizeOverride, positionOverride) => { const toVueNode = (node, sizeOverride, positionOverride) => {
const normalized = clone(node); const normalized = clone(node);
normalized.id ||= nodeId(); normalized.id ||= nodeId();
@ -98,6 +128,10 @@ const toVueNode = (node, sizeOverride, positionOverride) => {
}; };
}; };
/**
* 处理 toVueEdge 对应的数据或交互作用范围仅限画布适配层
* @param {*} edge 调用方传入的 edge 参数
*/
const toVueEdge = (edge) => { const toVueEdge = (edge) => {
const normalized = clone(edge); const normalized = clone(edge);
normalized.id ||= edgeId(); normalized.id ||= edgeId();
@ -124,7 +158,13 @@ const toVueEdge = (edge) => {
}; };
}; };
/**
* 关联 attachChildrenToGroups 对应的数据或交互作用范围仅限画布适配层
* @param {*} nodes 调用方传入的 nodes 参数
*/
const attachChildrenToGroups = (nodes) => { const attachChildrenToGroups = (nodes) => {
// 先建立节点索引和显式父子关系,再用旧数据中的 children 补齐缺失关系。
// 最后统一换算相对坐标,避免父节点尚未就绪时提前计算造成位置漂移。
const nodeLookup = new Map(nodes.map((node) => [node.id, node])); const nodeLookup = new Map(nodes.map((node) => [node.id, node]));
const declaredParents = new Map(); const declaredParents = new Map();
@ -200,9 +240,19 @@ export const createFlowFacade = (store) => {
let history = []; let history = [];
let historyIndex = -1; let historyIndex = -1;
/**
* 获取 getNodes 对应的数据或交互作用范围仅限画布适配层
*/
const getNodes = () => store.getNodes.value || []; const getNodes = () => store.getNodes.value || [];
/**
* 获取 getEdges 对应的数据或交互作用范围仅限画布适配层
*/
const getEdges = () => store.getEdges.value || []; const getEdges = () => store.getEdges.value || [];
/**
* 处理 backendNode 对应的数据或交互作用范围仅限画布适配层
* @param {*} node 当前流程节点
*/
const backendNode = (node) => { const backendNode = (node) => {
const result = clone(node.data.backend); const result = clone(node.data.backend);
const size = { const size = {
@ -242,6 +292,10 @@ export const createFlowFacade = (store) => {
return result; return result;
}; };
/**
* 处理 backendEdge 对应的数据或交互作用范围仅限画布适配层
* @param {*} edge 调用方传入的 edge 参数
*/
const backendEdge = (edge) => ({ const backendEdge = (edge) => ({
...clone(edge.data?.backend), ...clone(edge.data?.backend),
id: edge.id, id: edge.id,
@ -252,10 +306,18 @@ export const createFlowFacade = (store) => {
targetAnchorId: edge.targetHandle || `${edge.target}_3`, targetAnchorId: edge.targetHandle || `${edge.target}_3`,
}); });
/**
* 处理 emit 对应的数据或交互作用范围仅限画布适配层
* @param {*} name 名称或事件名称
* @param {*} payload 事件数据
*/
const emit = (name, payload) => { const emit = (name, payload) => {
(handlers.get(name) || []).forEach((handler) => handler(payload)); (handlers.get(name) || []).forEach((handler) => handler(payload));
}; };
/**
* 处理 recordHistory 对应的数据或交互作用范围仅限画布适配层
*/
const recordHistory = () => { const recordHistory = () => {
if (historySuspended) return; if (historySuspended) return;
const graph = facade.getGraphData(); const graph = facade.getGraphData();
@ -267,12 +329,19 @@ export const createFlowFacade = (store) => {
historyIndex = history.length - 1; historyIndex = history.length - 1;
}; };
/**
* 更新 changed 对应的数据或交互作用范围仅限画布适配层
*/
const changed = () => { const changed = () => {
if (historySuspended) return; if (historySuspended) return;
recordHistory(); recordHistory();
emit("history:change", { data: facade.getGraphData() }); emit("history:change", { data: facade.getGraphData() });
}; };
/**
* 获取 getNodeRect 对应的数据或交互作用范围仅限画布适配层
* @param {*} node 当前流程节点
*/
const getNodeRect = (node) => { const getNodeRect = (node) => {
const parent = node.parentNode ? store.findNode(node.parentNode) : null; const parent = node.parentNode ? store.findNode(node.parentNode) : null;
const parentPosition = parent?.position || parent?.computedPosition || { x: 0, y: 0 }; const parentPosition = parent?.position || parent?.computedPosition || { x: 0, y: 0 };
@ -287,9 +356,17 @@ export const createFlowFacade = (store) => {
}; };
}; };
/**
* 获取 getLoopLayoutState 对应的数据或交互作用范围仅限画布适配层
* @param {*} group 调用方传入的 group 参数
*/
const getLoopLayoutState = (group) => { const getLoopLayoutState = (group) => {
const current = getNodeRect(group); const current = getNodeRect(group);
const existing = loopLayoutStates.get(group.id); const existing = loopLayoutStates.get(group.id);
/**
* 处理 if 对应的数据或交互作用范围仅限画布适配层
* @param {*} !existing 调用方传入的 !existing 参数
*/
if (!existing) { if (!existing) {
const state = { base: { ...current }, last: { ...current } }; const state = { base: { ...current }, last: { ...current } };
loopLayoutStates.set(group.id, state); loopLayoutStates.set(group.id, state);
@ -298,6 +375,10 @@ export const createFlowFacade = (store) => {
const sizeChanged = Math.abs(current.width - existing.last.width) > 1 const sizeChanged = Math.abs(current.width - existing.last.width) > 1
|| Math.abs(current.height - existing.last.height) > 1; || Math.abs(current.height - existing.last.height) > 1;
/**
* 处理 if 对应的数据或交互作用范围仅限画布适配层
* @param {*} sizeChanged 调用方传入的 sizeChanged 参数
*/
if (sizeChanged) { if (sizeChanged) {
existing.base = { ...current }; existing.base = { ...current };
} else { } else {
@ -310,6 +391,12 @@ export const createFlowFacade = (store) => {
return existing; return existing;
}; };
/**
* 布局 layoutLoop 对应的数据或交互作用范围仅限画布适配层
* @param {*} group 调用方传入的 group 参数
* @param {*} activeChildId 调用方传入的 activeChildId 参数
* @param {*} activePosition 调用方传入的 activePosition 参数
*/
const layoutLoop = (group, activeChildId, activePosition) => { const layoutLoop = (group, activeChildId, activePosition) => {
const state = getLoopLayoutState(group); const state = getLoopLayoutState(group);
const children = getNodes().filter((node) => node.parentNode === group.id); const children = getNodes().filter((node) => node.parentNode === group.id);
@ -365,8 +452,16 @@ export const createFlowFacade = (store) => {
return true; return true;
}; };
/**
* 获取 getAnchors 对应的数据或交互作用范围仅限画布适配层
* @param {*} node 当前流程节点
*/
const getAnchors = (node) => { const getAnchors = (node) => {
const type = node.data.flowType; const type = node.data.flowType;
/**
* 处理 if 对应的数据或交互作用范围仅限画布适配层
* @param {*} type 目标类型
*/
if (type === "branch") { if (type === "branch") {
return [ return [
{ id: `${node.id}_entry`, name: "left" }, { id: `${node.id}_entry`, name: "left" },
@ -382,6 +477,10 @@ export const createFlowFacade = (store) => {
]; ];
}; };
/**
* 处理 modelFor 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
*/
const modelFor = (id) => { const modelFor = (id) => {
const node = store.findNode(id); const node = store.findNode(id);
if (!node) return null; if (!node) return null;
@ -415,31 +514,58 @@ export const createFlowFacade = (store) => {
}; };
const facade = { const facade = {
/**
* 订阅 on 对应的数据或交互作用范围仅限画布适配层
* @param {*} name 名称或事件名称
* @param {*} handler 事件处理函数
*/
on(name, handler) { on(name, handler) {
const list = handlers.get(name) || []; const list = handlers.get(name) || [];
list.push(handler); list.push(handler);
handlers.set(name, list); handlers.set(name, list);
return () => facade.off(name, handler); return () => facade.off(name, handler);
}, },
/**
* 订阅 once 对应的数据或交互作用范围仅限画布适配层
* @param {*} name 名称或事件名称
* @param {*} handler 事件处理函数
*/
once(name, handler) { once(name, handler) {
/**
* 处理 wrapped 对应的数据或交互作用范围仅限画布适配层
* @param {*} payload 事件数据
*/
const wrapped = (payload) => { const wrapped = (payload) => {
facade.off(name, wrapped); facade.off(name, wrapped);
handler(payload); handler(payload);
}; };
facade.on(name, wrapped); facade.on(name, wrapped);
}, },
/**
* 取消订阅 off 对应的数据或交互作用范围仅限画布适配层
* @param {*} name 名称或事件名称
* @param {*} handler 事件处理函数
*/
off(name, handler) { off(name, handler) {
if (!handler) handlers.delete(name); if (!handler) handlers.delete(name);
else handlers.set(name, (handlers.get(name) || []).filter((item) => item !== handler)); else handlers.set(name, (handlers.get(name) || []).filter((item) => item !== handler));
}, },
emit, emit,
markChanged: changed, markChanged: changed,
/**
* 获取 getGraphData 对应的数据或交互作用范围仅限画布适配层
*/
getGraphData() { getGraphData() {
return { return {
nodes: getNodes().map(backendNode), nodes: getNodes().map(backendNode),
edges: getEdges().map(backendEdge), edges: getEdges().map(backendEdge),
}; };
}, },
/**
* 渲染 render 对应的数据或交互作用范围仅限画布适配层
* @param {*} graph 调用方传入的 graph 参数
* @param {*} options 行为配置
*/
render(graph, options = {}) { render(graph, options = {}) {
historySuspended = true; historySuspended = true;
loopLayoutStates.clear(); loopLayoutStates.clear();
@ -456,6 +582,9 @@ export const createFlowFacade = (store) => {
})) }))
: options.nodePositions; : options.nodePositions;
const data = toVueFlowData(graph, { nodeSizes, nodePositions }); const data = toVueFlowData(graph, { nodeSizes, nodePositions });
/**
* 处理 finishRender 对应的数据或交互作用范围仅限画布适配层
*/
const finishRender = () => { const finishRender = () => {
historySuspended = false; historySuspended = false;
if (options.resetHistory !== false) { if (options.resetHistory !== false) {
@ -465,6 +594,9 @@ export const createFlowFacade = (store) => {
} }
nextTick(() => store.updateNodeInternals()); nextTick(() => store.updateNodeInternals());
}; };
/**
* 处理 applyData 对应的数据或交互作用范围仅限画布适配层
*/
const applyData = () => { const applyData = () => {
store.setNodes(data.nodes); store.setNodes(data.nodes);
store.setEdges(data.edges); store.setEdges(data.edges);
@ -482,12 +614,20 @@ export const createFlowFacade = (store) => {
applyData(); applyData();
} }
}, },
/**
* 新增 addNode 对应的数据或交互作用范围仅限画布适配层
* @param {*} node 当前流程节点
*/
addNode(node) { addNode(node) {
const vueNode = toVueNode(node); const vueNode = toVueNode(node);
store.addNodes(vueNode); store.addNodes(vueNode);
changed(); changed();
return backendNode(vueNode); return backendNode(vueNode);
}, },
/**
* 删除 deleteNode 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
*/
deleteNode(id) { deleteNode(id) {
const target = store.findNode(id); const target = store.findNode(id);
if (target?.data?.flowType === "selectArea") { if (target?.data?.flowType === "selectArea") {
@ -513,6 +653,10 @@ export const createFlowFacade = (store) => {
changed(); changed();
if (parentId) nextTick(() => facade.resizeGroupToChildren(parentId)); if (parentId) nextTick(() => facade.resizeGroupToChildren(parentId));
}, },
/**
* 新增 addEdge 对应的数据或交互作用范围仅限画布适配层
* @param {*} edge 调用方传入的 edge 参数
*/
addEdge(edge) { addEdge(edge) {
const vueEdge = toVueEdge(edge); const vueEdge = toVueEdge(edge);
const source = store.findNode(vueEdge.source); const source = store.findNode(vueEdge.source);
@ -522,17 +666,34 @@ export const createFlowFacade = (store) => {
changed(); changed();
return backendEdge(vueEdge); return backendEdge(vueEdge);
}, },
/**
* 删除 deleteEdge 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
*/
deleteEdge(id) { deleteEdge(id) {
store.removeEdges(id); store.removeEdges(id);
changed(); changed();
}, },
/**
* 删除 deleteEdgeByNodeId 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
*/
deleteEdgeByNodeId(id) { deleteEdgeByNodeId(id) {
store.removeEdges(getEdges().filter((edge) => edge.source === id || edge.target === id)); store.removeEdges(getEdges().filter((edge) => edge.source === id || edge.target === id));
changed(); changed();
}, },
/**
* 获取 getProperties 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
*/
getProperties(id) { getProperties(id) {
return clone(store.findNode(id)?.data?.properties || {}); return clone(store.findNode(id)?.data?.properties || {});
}, },
/**
* 设置 setProperties 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
* @param {*} properties 调用方传入的 properties 参数
*/
setProperties(id, properties) { setProperties(id, properties) {
const node = store.findNode(id); const node = store.findNode(id);
if (!node) return; if (!node) return;
@ -541,15 +702,25 @@ export const createFlowFacade = (store) => {
changed(); changed();
}, },
getNodeModelById: modelFor, getNodeModelById: modelFor,
/**
* 获取 getSelectElements 对应的数据或交互作用范围仅限画布适配层
*/
getSelectElements() { getSelectElements() {
return { return {
nodes: (store.getSelectedNodes.value || []).map(backendNode), nodes: (store.getSelectedNodes.value || []).map(backendNode),
edges: (store.getSelectedEdges.value || []).map(backendEdge), edges: (store.getSelectedEdges.value || []).map(backendEdge),
}; };
}, },
/**
* 清理 clearSelectElements 对应的数据或交互作用范围仅限画布适配层
*/
clearSelectElements() { clearSelectElements() {
store.removeSelectedElements(); store.removeSelectedElements();
}, },
/**
* 处理 selectElementById 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
*/
selectElementById(id) { selectElementById(id) {
store.removeSelectedElements(); store.removeSelectedElements();
if (!id) return; if (!id) return;
@ -558,33 +729,63 @@ export const createFlowFacade = (store) => {
const edge = store.findEdge(id); const edge = store.findEdge(id);
if (edge) store.addSelectedEdges([edge]); if (edge) store.addSelectedEdges([edge]);
}, },
/**
* 处理 selectElementsByIds 对应的数据或交互作用范围仅限画布适配层
* @param {*} ids 调用方传入的 ids 参数
*/
selectElementsByIds(ids = []) { selectElementsByIds(ids = []) {
store.removeSelectedElements(); store.removeSelectedElements();
const nodes = ids.map((id) => store.findNode(id)).filter(Boolean); const nodes = ids.map((id) => store.findNode(id)).filter(Boolean);
if (nodes.length) store.addSelectedNodes(nodes); if (nodes.length) store.addSelectedNodes(nodes);
}, },
/**
* 处理 focusOn 对应的数据或交互作用范围仅限画布适配层
* @param {*} { id } 调用方传入的 { id } 参数
*/
focusOn({ id }) { focusOn({ id }) {
const node = store.findNode(id); const node = store.findNode(id);
if (!node) return; if (!node) return;
const center = backendNode(node); const center = backendNode(node);
store.setCenter(center.x, center.y, { zoom: Math.max(store.viewport.value?.zoom || 1, 0.7), duration: 300 }); store.setCenter(center.x, center.y, { zoom: Math.max(store.viewport.value?.zoom || 1, 0.7), duration: 300 });
}, },
/**
* 处理 fitView 对应的数据或交互作用范围仅限画布适配层
*/
fitView() { fitView() {
return store.fitView({ padding: 0.18, duration: 300 }); return store.fitView({ padding: 0.18, duration: 300 });
}, },
/**
* 处理 translateCenter 对应的数据或交互作用范围仅限画布适配层
*/
translateCenter() { translateCenter() {
return facade.fitView(); return facade.fitView();
}, },
/**
* 缩放 zoom 对应的数据或交互作用范围仅限画布适配层
* @param {*} scale 缩放比例
* @param {*} center 缩放中心
*/
zoom(scale, center) { zoom(scale, center) {
if (Array.isArray(center) && center.length === 2) { if (Array.isArray(center) && center.length === 2) {
return store.setCenter(center[0], center[1], { zoom: scale, duration: 250 }); return store.setCenter(center[0], center[1], { zoom: scale, duration: 250 });
} }
return store.zoomTo(scale, { duration: 250 }); return store.zoomTo(scale, { duration: 250 });
}, },
/**
* 获取 getPointByClient 对应的数据或交互作用范围仅限画布适配层
* @param {*} x 客户端横坐标
* @param {*} y 客户端纵坐标
*/
getPointByClient(x, y) { getPointByClient(x, y) {
const point = store.screenToFlowCoordinate({ x, y }); const point = store.screenToFlowCoordinate({ x, y });
return { canvasOverlayPosition: point, domOverlayPosition: point }; return { canvasOverlayPosition: point, domOverlayPosition: point };
}, },
/**
* 新增 addToGroup 对应的数据或交互作用范围仅限画布适配层
* @param {*} groupId 分组节点 ID
* @param {*} childId 子节点 ID
* @param {*} dropCenter 拖放中心坐标
*/
addToGroup(groupId, childId, dropCenter) { addToGroup(groupId, childId, dropCenter) {
const group = store.findNode(groupId); const group = store.findNode(groupId);
const child = store.findNode(childId); const child = store.findNode(childId);
@ -610,7 +811,14 @@ export const createFlowFacade = (store) => {
changed(); changed();
}); });
}, },
/**
* 编组 groupNodes 对应的数据或交互作用范围仅限画布适配层
* @param {*} groupNode 调用方传入的 groupNode 参数
* @param {*} childIds 子节点 ID 集合
*/
groupNodes(groupNode, childIds = []) { groupNodes(groupNode, childIds = []) {
// 先计算选中节点的外接矩形确定容器尺寸,再把子节点坐标转换为容器内相对坐标。
// 与分组外节点相连的边保持不变,此处仅更新节点层级和几何信息。
const graph = facade.getGraphData(); const graph = facade.getGraphData();
const selectedIds = new Set(childIds); const selectedIds = new Set(childIds);
const children = graph.nodes.filter((node) => ( const children = graph.nodes.filter((node) => (
@ -641,6 +849,10 @@ export const createFlowFacade = (store) => {
}); });
return clone(group); return clone(group);
}, },
/**
* 处理 ungroup 对应的数据或交互作用范围仅限画布适配层
* @param {*} groupId 分组节点 ID
*/
ungroup(groupId) { ungroup(groupId) {
const graph = facade.getGraphData(); const graph = facade.getGraphData();
const group = graph.nodes.find((node) => node.id === groupId && node.type === "selectArea"); const group = graph.nodes.find((node) => node.id === groupId && node.type === "selectArea");
@ -668,6 +880,10 @@ export const createFlowFacade = (store) => {
}); });
return true; return true;
}, },
/**
* 准备 prepareLoopChildDrag 对应的数据或交互作用范围仅限画布适配层
* @param {*} childId 子节点 ID
*/
prepareLoopChildDrag(childId) { prepareLoopChildDrag(childId) {
const child = store.findNode(childId); const child = store.findNode(childId);
const group = child?.parentNode ? store.findNode(child.parentNode) : null; const group = child?.parentNode ? store.findNode(child.parentNode) : null;
@ -680,16 +896,35 @@ export const createFlowFacade = (store) => {
const rect = getNodeRect(child); const rect = getNodeRect(child);
return { groupId: group.id, position: { x: rect.x, y: rect.y } }; return { groupId: group.id, position: { x: rect.x, y: rect.y } };
}, },
/**
* 布局 layoutLoopDuringDrag 对应的数据或交互作用范围仅限画布适配层
* @param {*} groupId 分组节点 ID
* @param {*} childId 子节点 ID
* @param {*} position 调用方传入的 position 参数
*/
layoutLoopDuringDrag(groupId, childId, position) { layoutLoopDuringDrag(groupId, childId, position) {
const group = store.findNode(groupId); const group = store.findNode(groupId);
if (!group || group.data.flowType !== "loop" || !position) return; if (!group || group.data.flowType !== "loop" || !position) return;
layoutLoop(group, childId, position); layoutLoop(group, childId, position);
}, },
/**
* 调整 resizeGroupToChildren 对应的数据或交互作用范围仅限画布适配层
* @param {*} groupId 分组节点 ID
* @param {*} options 行为配置
*/
resizeGroupToChildren(groupId, options = {}) { resizeGroupToChildren(groupId, options = {}) {
// 循环容器沿用统一的内边距和最小尺寸约束,并按配置决定是否记录变更。
// 拖拽过程可关闭变更标记,避免高频移动产生多余历史记录。
const group = store.findNode(groupId); const group = store.findNode(groupId);
if (!group || group.data.flowType !== "loop") return; if (!group || group.data.flowType !== "loop") return;
if (layoutLoop(group) && options.markChanged !== false) changed(); if (layoutLoop(group) && options.markChanged !== false) changed();
}, },
/**
* 移动 moveNodeBy 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
* @param {*} dx 横向位移
* @param {*} dy 纵向位移
*/
moveNodeBy(id, dx, dy) { moveNodeBy(id, dx, dy) {
const node = store.findNode(id); const node = store.findNode(id);
if (!node) return; if (!node) return;
@ -701,6 +936,9 @@ export const createFlowFacade = (store) => {
}); });
changed(); changed();
}, },
/**
* 撤销 undo 对应的数据或交互作用范围仅限画布适配层
*/
undo() { undo() {
if (historyIndex <= 0) return false; if (historyIndex <= 0) return false;
historyIndex -= 1; historyIndex -= 1;
@ -709,6 +947,9 @@ export const createFlowFacade = (store) => {
nextTick(() => emit("history:change", { data: facade.getGraphData() })); nextTick(() => emit("history:change", { data: facade.getGraphData() }));
return true; return true;
}, },
/**
* 重做 redo 对应的数据或交互作用范围仅限画布适配层
*/
redo() { redo() {
if (historyIndex >= history.length - 1) return false; if (historyIndex >= history.length - 1) return false;
historyIndex += 1; historyIndex += 1;
@ -717,6 +958,11 @@ export const createFlowFacade = (store) => {
nextTick(() => emit("history:change", { data: facade.getGraphData() })); nextTick(() => emit("history:change", { data: facade.getGraphData() }));
return true; return true;
}, },
/**
* 注册 registerComponentInstance 对应的数据或交互作用范围仅限画布适配层
* @param {*} id 目标元素 ID
* @param {*} instance 组件实例
*/
registerComponentInstance(id, instance) { registerComponentInstance(id, instance) {
if (instance) componentInstances.set(id, instance); if (instance) componentInstances.set(id, instance);
}, },