179 lines
5.7 KiB
TypeScript
179 lines
5.7 KiB
TypeScript
import type { FlowNode } from '@/pages/Workflow/Design/types';
|
||
|
||
/**
|
||
* 正则1:匹配 ${...} 块
|
||
*/
|
||
const BLOCK_PATTERN = /\$\{([^}]+)\}/g;
|
||
|
||
/**
|
||
* 正则2:在表达式内匹配 节点名.字段 引用
|
||
* 支持中文节点名、UUID格式节点ID
|
||
*/
|
||
const NODE_REF_PATTERN = /([a-zA-Z0-9_\u4e00-\u9fa5\-]+)\.([a-zA-Z0-9_.]+)/g;
|
||
|
||
/**
|
||
* 将显示名称格式转换为UUID格式
|
||
* ${节点名称.字段名} → ${节点UUID.字段名}
|
||
*
|
||
* @param displayText 包含显示名称的文本
|
||
* @param allNodes 所有节点列表(用于查找UUID)
|
||
* @returns 转换后的UUID格式文本
|
||
*
|
||
* @example
|
||
* convertToUUID("构建${Jenkins构建.buildStatus}完成", allNodes)
|
||
* // 返回: "构建${uuid-123.buildStatus}完成"
|
||
*/
|
||
export const convertToUUID = (
|
||
displayText: string,
|
||
allNodes: FlowNode[]
|
||
): string => {
|
||
if (!displayText || typeof displayText !== 'string') {
|
||
return displayText;
|
||
}
|
||
|
||
// 阶段1:处理 ${...} 块
|
||
return displayText.replace(BLOCK_PATTERN, (blockMatch, blockContent) => {
|
||
// 阶段2:在块内容中查找并替换所有 节点名.字段 引用
|
||
const transformedContent = blockContent.replace(NODE_REF_PATTERN, (refMatch: string, nodeNameOrId: string, fieldPath: string) => {
|
||
// 特殊处理:表单字段
|
||
if (nodeNameOrId === '启动表单' || nodeNameOrId === 'form' || nodeNameOrId === 'notification') {
|
||
return `${nodeNameOrId}.${fieldPath}`;
|
||
}
|
||
|
||
// 尝试通过名称查找节点
|
||
const nodeByName = allNodes.find(n => {
|
||
const nodeName = n.data?.label || n.data?.nodeDefinition?.nodeName;
|
||
return nodeName === nodeNameOrId;
|
||
});
|
||
|
||
if (nodeByName) {
|
||
return `${nodeByName.id}.${fieldPath}`;
|
||
}
|
||
|
||
// 可能已经是UUID格式,保持原样
|
||
return refMatch;
|
||
});
|
||
|
||
return `\${${transformedContent}}`;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 将UUID格式转换为显示名称格式
|
||
* ${节点UUID.字段名} → ${节点名称.字段名}
|
||
*
|
||
* @param uuidText 包含UUID的文本
|
||
* @param allNodes 所有节点列表(用于查找显示名称)
|
||
* @returns 转换后的显示名称格式文本
|
||
*
|
||
* @example
|
||
* convertToDisplayName("构建${uuid-123.buildStatus}完成", allNodes)
|
||
* // 返回: "构建${Jenkins构建.buildStatus}完成"
|
||
*/
|
||
export const convertToDisplayName = (
|
||
uuidText: string,
|
||
allNodes: FlowNode[]
|
||
): string => {
|
||
if (!uuidText || typeof uuidText !== 'string') {
|
||
return uuidText;
|
||
}
|
||
|
||
// 阶段1:处理 ${...} 块
|
||
return uuidText.replace(BLOCK_PATTERN, (blockMatch, blockContent) => {
|
||
// 阶段2:在块内容中查找并替换所有 UUID.字段 引用为 节点名.字段
|
||
const transformedContent = blockContent.replace(NODE_REF_PATTERN, (refMatch: string, nodeIdOrName: string, fieldPath: string) => {
|
||
// 特殊处理:表单字段
|
||
if (nodeIdOrName === 'form' || nodeIdOrName === '启动表单' || nodeIdOrName === 'notification') {
|
||
return `${nodeIdOrName}.${fieldPath}`;
|
||
}
|
||
|
||
// 尝试通过UUID查找节点
|
||
const nodeById = allNodes.find(n => n.id === nodeIdOrName);
|
||
|
||
if (nodeById) {
|
||
// 找到了,替换为显示名称
|
||
const nodeName = nodeById.data?.label || nodeById.data?.nodeDefinition?.nodeName || nodeIdOrName;
|
||
return `${nodeName}.${fieldPath}`;
|
||
}
|
||
|
||
// 可能已经是显示名称格式,保持原样
|
||
return refMatch;
|
||
});
|
||
|
||
return `\${${transformedContent}}`;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 转换对象中的所有字符串值(从显示名称到UUID)
|
||
* 递归处理嵌套对象和数组
|
||
*
|
||
* @param obj 要转换的对象
|
||
* @param allNodes 所有节点列表
|
||
* @returns 转换后的对象
|
||
*/
|
||
export const convertObjectToUUID = <T extends Record<string, any>>(
|
||
obj: T,
|
||
allNodes: FlowNode[]
|
||
): T => {
|
||
if (!obj || typeof obj !== 'object') {
|
||
return obj;
|
||
}
|
||
|
||
const result: any = Array.isArray(obj) ? [] : {};
|
||
|
||
for (const key in obj) {
|
||
const value = obj[key];
|
||
|
||
if (typeof value === 'string') {
|
||
// 字符串类型:进行转换
|
||
result[key] = convertToUUID(value, allNodes);
|
||
} else if (value && typeof value === 'object') {
|
||
// 对象或数组:递归转换
|
||
result[key] = convertObjectToUUID(value, allNodes);
|
||
} else {
|
||
// 其他类型:保持原样
|
||
result[key] = value;
|
||
}
|
||
}
|
||
|
||
return result as T;
|
||
};
|
||
|
||
/**
|
||
* 转换对象中的所有字符串值(从UUID到显示名称)
|
||
* 递归处理嵌套对象和数组
|
||
*
|
||
* @param obj 要转换的对象
|
||
* @param allNodes 所有节点列表
|
||
* @returns 转换后的对象
|
||
*/
|
||
export const convertObjectToDisplayName = <T extends Record<string, any>>(
|
||
obj: T,
|
||
allNodes: FlowNode[]
|
||
): T => {
|
||
if (!obj || typeof obj !== 'object') {
|
||
return obj;
|
||
}
|
||
|
||
const result: any = Array.isArray(obj) ? [] : {};
|
||
|
||
for (const key in obj) {
|
||
const value = obj[key];
|
||
|
||
if (typeof value === 'string') {
|
||
// 字符串类型:进行转换
|
||
result[key] = convertToDisplayName(value, allNodes);
|
||
} else if (value && typeof value === 'object') {
|
||
// 对象或数组:递归转换
|
||
result[key] = convertObjectToDisplayName(value, allNodes);
|
||
} else {
|
||
// 其他类型:保持原样
|
||
result[key] = value;
|
||
}
|
||
}
|
||
|
||
return result as T;
|
||
};
|
||
|