CMVR-BID/src/views/flow/nodes/function/switch.js

319 lines
8.3 KiB
JavaScript
Raw Normal View History

2026-04-15 10:59:17 +08:00
// 导入 HtmlNode 及其模型,为后续继承做准备
import { HtmlNode, HtmlNodeModel, h as svgH } from "@logicflow/core";
// 导入 Vue 相关方法,用于渲染组件
import { createApp, h, nextTick } from "vue";
import ElementPlus from "element-plus";
// 导入 Vue 组件
import Switch from "./switch.vue";
import JsonViewer from 'vue3-json-viewer'
/**
* 定义一个 元素的 HTML 节点类,继承自 HtmlNode
* 该类负责在 HTML 中渲染 元素,并处理其交互逻辑
*/
class SwitchHtmlNode extends HtmlNode {
resizeObserver = null;
isMounted; // 标记组件是否已挂载
r; // 渲染函数
app; // Vue 应用实例
container = null;
static reusePool = new Map(); // 节点复用池
/**
* 构造函数
* @param props 传递给节点的属性,包括模型、图模型等
*/
constructor(props) {
super(props);
this.initVueApp(props);
}
initVueApp(props) {
this.isMounted = false;
this.hideAnchor = false;
this.autoExpand = true; // 防止锚点被折叠
this.anchorsPreset = "default"; // 重置锚点预设
// 创建 元素的渲染函数
this.r = h(Switch, {
model: props.model,
graphModel: props.graphModel,
properties: {
...props.model.getProperties(),
},
text: props.model.text.value,
onContentChange: this.handleContentChange.bind(this),
onBindRef: this.handleComponentInstance.bind(this),
// 添加锚点相关回调
onAddAnchor: this.handleAddAnchor.bind(this),
onRemoveAnchor: this.handleRemoveAnchor.bind(this),
onChangeAnchor: this.handleChangeAnchor.bind(this)
});
// 创建 Vue 应用实例,并指定渲染函数
this.app = createApp({
render: () => this.r,
});
}
/**
* 将 HTML 内容设置到指定的根元素上
* @param rootEl 根元素
*/
async setHtml(rootEl) {
const nodeId = this.props.model.id;
if (SwitchHtmlNode.reusePool.has(nodeId)) {
rootEl.appendChild(SwitchHtmlNode.reusePool.get(nodeId));
return;
}
if (!this.isMounted) {
this.isMounted = true;
this.container = document.createElement("div");
this.container.style.display = "inline-block"; // 关键:确保容器自适应内容
rootEl.appendChild(this.container);
this.app.use(ElementPlus);
this.app.use(JsonViewer);
this.app.mount(this.container);
await nextTick();
this.setupSizeObserver();
SwitchHtmlNode.reusePool.set(nodeId, this.container);
} else {
this.r.component.props.properties = this.props.model.getProperties();
}
}
/**
* 获取节点文本内容
* 对于元素,返回 null,因为其内容由特定组件渲染
* @returns {null}
*/
getText() {
return null;
}
handleComponentInstance(data) {
// 将组件实例保存到节点模型
this.props.model.setComponentInstance(data)
}
handleContentChange() {
// 内容变化时强制更新尺寸
this.updateNodeSize();
}
// 处理添加锚点
handleAddAnchor(height, anchorId) {
const { model } = this.props
model.addAnchor(height, anchorId)
}
// 处理删除锚点
handleRemoveAnchor(anchorId) {
this.props.model.removeAnchor(anchorId);
}
handleChangeAnchor(height, anchorId) {
const { model } = this.props
model.changeAnchorHeight(height, anchorId)
}
// 渲染完成后获取实际尺寸
updateNodeSize() {
if (this.container) {
const { SCALE_X, SCALE_Y } = this.props.graphModel.transformModel;
const node = this.container.querySelector(".node__container");
const rect = node.getBoundingClientRect();
this.props.model.updateSize(rect.width / SCALE_X, rect.height / SCALE_Y);
}
}
setupSizeObserver() {
// 首次渲染立即检测
requestAnimationFrame(() => {
this.updateNodeSize();
// 持续监听变化
this.resizeObserver = new ResizeObserver(() => {
this.updateNodeSize();
});
this.resizeObserver.observe(this.container);
});
}
// 组件卸载时移除监听
onDestroy() {
this.resizeObserver?.disconnect();
}
}
/**
* 定义一个元素的 HTML 模型类,继承自 HtmlNodeModel
* 该类主要设置节点的属性和样式
*/
class SwitchHtmlModel extends HtmlNodeModel {
initNodeData(data) {
super.initNodeData(data);
}
// 返回动态锚点
addAnchor(height, anchorId) {
const properties = this.getProperties()
const anchor = properties?.anchor || []
anchor.push({
id: anchorId,
name: 'right',
x: this.x,
y: this.y,
height
})
this.setProperties({
...properties,
anchor
})
this.getDefaultAnchor()
this.initNodeData(this)
}
removeAnchor(anchorId) {
const properties = this.getProperties()
const anchor = properties?.anchor || []
let nweAnchor = anchor.filter(item => item.id !== anchorId);
this.setProperties({
...properties,
anchor: nweAnchor
})
}
changeAnchorHeight(height, anchorId) {
const properties = this.getProperties()
const anchor = properties?.anchor || []
anchor.forEach(item => {
if (item.id === anchorId) {
item.height = height
}
})
this.setProperties({
...properties,
anchor
})
this.getDefaultAnchor()
this.initNodeData(this)
}
// 保存组件实例引用
setComponentInstance(instance) {
this.componentInstance = instance;
}
closePopover() {
this.componentInstance.closePopover()
}
// 验证表单
async validateForm() {
if (this.componentInstance && this.componentInstance.validate) {
try {
const result = await this.componentInstance.validate();
if (result) {
return { valid: true, message: "验证通过" };
} else {
return { valid: false, message: "验证失败" };
}
} catch {
return { valid: false, message: "验证失败" };
}
}
return { valid: true, message: "无验证方法" };
}
/**
* 设置节点属性
* 包括宽度、高度、文本编辑属性等
*/
setAttributes() {
// 初始设置为0,后续动态更新
this.width = 0;
this.height = 0;
this.text.editable = false;
}
updateSize(width, height) {
this.width = width + 24;
this.height = height + 50;
// const properties = lf.getProperties(this.id)
// this.setProperties({
// ...properties,
// width: this.width,
// height: this.height
// })
this.initNodeData(this); // 触发节点重绘
}
// 定义节点只有左右两个锚点. 锚点位置通过中心点和宽度算出来。
getDefaultAnchor() {
let _a = this,
x = _a.x,
y = _a.y,
width = _a.width,
height = _a.height;
const properties = this.getProperties()
const anchor = properties?.anchor || []
// const { SCALE_Y } = this.graphModel.transformModel;
const ids = []
anchor.forEach(item => {
ids.push(item.id)
if (item.id !== "".concat(this.id, "_else")) {
item.x = x + width / 2 - 40
// item.y = (y - height / 2 + item.height + 60) / SCALE_Y
item.y = y - height / 2 + item.height + 60
} else {
item.x = x + width / 2 - 40
item.y = y + height / 2 - 80
}
})
return [
// {
// x: x + width / 2 - 40,
// y: y + height / 2 - 80,
// name: "right",
// id: "".concat(this.id, "_else")
// },
{
x: x - width / 2,
y: y - 25,
name: "left",
id: "".concat(this.id, "_entry")
},
...anchor
];
}
/**
* 获取节点轮廓样式
* 覆盖父类方法,设置 stroke 属性为 none,以适应特定的视觉效果
* @returns {object} 节点轮廓样式
*/
getOutlineStyle() {
const style = super.getOutlineStyle();
style.stroke = "none";
2026-07-08 11:09:51 +08:00
// style.hover.stroke = "none";
2026-04-15 10:59:17 +08:00
return style;
}
}
// 导出方法注册
export function registerSwitch(lf) {
lf.register({
type: "branch",
view: SwitchHtmlNode,
model: SwitchHtmlModel,
});
}