logicFlow ,画布节点自定义
getShape() {
const { model } = this.props;
const { x, y, width, height } = model;
const style = model.getNodeStyle();
// 1. 基础矩形
const rect = h('rect', {
...style,
x: x - width / 2,
y: y - height / 2,
width,
height,
rx: style.borderRadius,
ry: style.borderRadius,
});
// 2. 获取文本元素
const text = this.getText();
// 3. 获取并创建icon元素
const { icon } = model.properties;
let iconEl = null;
if (icon) {
iconEl = h('image', {
x: x - width / 2 + 5, // 5px 左边距
y: y - height / 2 + 5, // 5px 上边距
width: 20,
height: 20,
href: icon,
});
}
// 4. 组合所有元素
return h('g', {}, [rect, text, iconEl]);
}
function startDrag(type: string, item: PaletteItem) {
isDraggingFromPalette = true; // 设置拖动状态标志
hideNodeTooltip();
if (!lf) return;
const { label: text, key, icon } = item;
console.log('开始拖拽,参数:', { type, text, key, icon });
currentDragKey = key || null;
const dragData = {
type,
text,
properties: {
paletteKey: key,
icon: icon // 传递icon属性
} as any
};
console.log('拖拽数据:', dragData);
try {
lf.dnd.startDrag(dragData);
console.log('拖拽启动成功');
} catch (error) {
console.error('拖拽启动失败:', error);
}
}
// 监听选中的组件类型变化,改变对应画布节点的背景色
watch(selectedComponentType, (newType) => {
if (!lf) return;
const graphData = lf.getGraphData();
graphData.nodes.forEach(node => {
const nodeModel = lf.getNodeModelById(node.id);
if (nodeModel) {
const { componentType } = nodeModel.properties;
let newBackgroundColor = '#f0f9ff'; // 默认颜色
// 如果选中了“全部”,或者当前节点的类型与选中类型匹配,则应用高亮颜色
if (newType === 'all' || componentType === newType) {
const typeConfig = componentTypes.value.find(t => t.key === componentType);
if (typeConfig) {
newBackgroundColor = typeConfig.color;
}
}
// 设置 backgroundColor 属性
nodeModel.setProperties({
backgroundColor: newBackgroundColor
});
// 显式更新样式以触发重绘
nodeModel.updateStyles();
}
});
});
getNodeStyle() {
const style = super.getNodeStyle()
const { isUnconnected, isHighlighted } = this.properties
let stroke = '#3b82f6' // 默认颜色
let strokeWidth = 2
if (isHighlighted) {
stroke = '#f59e0b' // 高亮颜色
strokeWidth = 3
}
if (isUnconnected) {
stroke = '#ef4444' // 未连接状态的颜色优先级更高
strokeWidth = 3
}
// Directly modify the style object from the super class
style.fill = this.properties.backgroundColor || '#f0f9ff';
style.stroke = stroke;
style.strokeWidth = strokeWidth;
style.borderRadius = 8;
return style;
}
// 重写getData方法,确保自定义属性被序列化
getData() {
const data = super.getData();
data.properties = {
...data.properties,
backgroundColor: this.properties.backgroundColor
};
return data;
}
// 监听 History 撤销/重做及历史状态变化
lf.on('history:undo', () => {
console.log('[Control] 撤销(上一步)完成')
})
lf.on('history:redo', () => {
console.log('[Control] 重做(下一步)完成')
})
lf.on('history:change', ({ data }) => {
const { undoAble, redoAble, canUndo, canRedo } = data || {}
const canUndoNow = typeof undoAble === 'boolean' ? undoAble : !!canUndo
const canRedoNow = typeof redoAble === 'boolean' ? redoAble : !!canRedo
console.log('[Control] 历史状态变化 -> canUndo:', canUndoNow, 'canRedo:', canRedoNow, data)
})
// 可选:监听 Control 按钮点击(不同版本可能没有该事件)
lf.on?.('control:click', (payload) => {
console.log('[Control] 按钮点击:', payload)
})
// 兜底:劫持 undo/redo 方法,确保任何来源都会打印日志
if (typeof lf.undo === 'function') {
const origUndo = lf.undo.bind(lf)
lf.undo = (...args) => {
const ret = origUndo(...args)
try { console.log('[Control] 撤销(上一步)完成(hook)') } catch {}
return ret
}
}
if (typeof lf.redo === 'function') {
const origRedo = lf.redo.bind(lf)
lf.redo = (...args) => {
const ret = origRedo(...args)
try { console.log('[Control] 重做(下一步)完成(hook)') } catch {}
return ret
}
}
function isValidURL(url) {
const urlPattern = /^(https?:\/\/)?(www\.)?([a-zA-Z0-9-]+(\.[a-zA-Z]{2,})+)(:[0-9]{1,5})?(\/[^\s]*)?$/;
return urlPattern.test(url);
}

浙公网安备 33010602011771号