2026-02-26 11:45:32 +08:00
|
|
|
import { ref, computed } from "vue";
|
2026-03-12 17:07:04 +08:00
|
|
|
import { NODE_TYPE, NODE_DATATYPE } from '../tools/index.d'
|
2026-03-05 15:13:16 +08:00
|
|
|
import { ElMessageBox } from 'element-plus'
|
2026-03-05 15:59:04 +08:00
|
|
|
import i18n from '@/lang'
|
|
|
|
|
const t = i18n.global.t
|
2026-02-26 11:45:32 +08:00
|
|
|
|
2026-02-27 14:58:36 +08:00
|
|
|
export interface NodesItem {
|
|
|
|
|
id: string
|
|
|
|
|
type: string
|
|
|
|
|
class: string
|
|
|
|
|
position: { x: number, y: number }
|
2026-03-05 10:38:33 +08:00
|
|
|
data: { component: any, type: string, superiorID?: string }
|
2026-02-27 14:58:36 +08:00
|
|
|
}
|
2026-02-26 11:45:32 +08:00
|
|
|
export class StateManager {
|
|
|
|
|
vueFlow: any
|
2026-03-05 13:46:10 +08:00
|
|
|
activeNodeID: any
|
2026-02-26 11:45:32 +08:00
|
|
|
nodes: any
|
2026-02-27 11:43:27 +08:00
|
|
|
nodes_: any
|
2026-02-26 11:45:32 +08:00
|
|
|
edges: any
|
|
|
|
|
zoom: any
|
2026-03-04 15:06:22 +08:00
|
|
|
tool: any
|
|
|
|
|
cursor: any
|
2026-03-05 10:18:10 +08:00
|
|
|
// 节点是否可拖动
|
2026-03-04 15:06:22 +08:00
|
|
|
nodesDraggable: any
|
2026-03-05 10:18:10 +08:00
|
|
|
// 拖动时是否可以平移画布
|
2026-03-04 15:06:22 +08:00
|
|
|
panOnDrag: any
|
|
|
|
|
|
2026-03-05 10:18:10 +08:00
|
|
|
// 历史记录-撤回/重做
|
|
|
|
|
mxHistory: any
|
|
|
|
|
historyList: any
|
|
|
|
|
historyIndex: any
|
|
|
|
|
|
2026-03-04 15:06:22 +08:00
|
|
|
// 管理器
|
2026-02-27 09:56:49 +08:00
|
|
|
eventManager: any
|
|
|
|
|
flowManager: any
|
|
|
|
|
nodeManager: any
|
2026-03-04 15:06:22 +08:00
|
|
|
toolManager: any
|
2026-03-12 17:07:04 +08:00
|
|
|
generateManager: any
|
2026-02-27 09:56:49 +08:00
|
|
|
// 设置管理器
|
|
|
|
|
setManager(options) {
|
|
|
|
|
options.eventManager && (this.eventManager = options.eventManager)
|
|
|
|
|
options.flowManager && (this.flowManager = options.flowManager)
|
|
|
|
|
options.nodeManager && (this.nodeManager = options.nodeManager)
|
2026-03-04 15:06:22 +08:00
|
|
|
options.toolManager && (this.toolManager = options.toolManager)
|
2026-03-12 17:07:04 +08:00
|
|
|
options.generateManager && (this.generateManager = options.generateManager)
|
2026-02-27 09:56:49 +08:00
|
|
|
}
|
2026-02-26 11:45:32 +08:00
|
|
|
constructor(options) {
|
|
|
|
|
this.vueFlow = options.vueFlow
|
2026-03-03 11:10:43 +08:00
|
|
|
this.zoom = ref(1)
|
2026-03-04 15:06:22 +08:00
|
|
|
this.tool = ref("")
|
|
|
|
|
this.cursor = ref("")
|
|
|
|
|
this.nodesDraggable = ref(false)
|
|
|
|
|
this.panOnDrag = ref(false)
|
2026-03-05 10:18:10 +08:00
|
|
|
this.mxHistory = ref(50)
|
|
|
|
|
this.historyList = ref([])
|
|
|
|
|
this.historyIndex = ref(0)
|
|
|
|
|
|
2026-03-05 13:46:10 +08:00
|
|
|
this.activeNodeID = ref("")
|
2026-02-27 14:58:36 +08:00
|
|
|
this.nodes = ref<NodesItem[]>([]);
|
2026-02-27 11:43:27 +08:00
|
|
|
this.nodes_ = computed(() => {
|
|
|
|
|
return this.nodes.value.map((node, index) => {
|
2026-03-03 15:39:54 +08:00
|
|
|
const obj = node;
|
|
|
|
|
const superiorID = node.data.superiorID;
|
|
|
|
|
const isSuperior = this.nodes.value.some((v) => v.id === superiorID)
|
|
|
|
|
const isSubord = this.nodes.value.some((v) => v.data.superiorID === node.id)
|
2026-03-04 15:06:22 +08:00
|
|
|
if (!isSuperior && isSubord) {// 没有上级 有下级
|
2026-02-27 14:58:36 +08:00
|
|
|
obj.type = NODE_TYPE.INPUT;
|
2026-03-04 15:06:22 +08:00
|
|
|
} else if (isSuperior && isSubord) {// 有上级 有下级
|
2026-02-27 14:58:36 +08:00
|
|
|
obj.type = NODE_TYPE.SECONDARY;
|
2026-03-04 15:06:22 +08:00
|
|
|
} else if (isSuperior && !isSubord) {// 有上级 没有下级
|
2026-03-03 15:39:54 +08:00
|
|
|
obj.type = NODE_TYPE.OUTPUT;
|
2026-03-04 15:06:22 +08:00
|
|
|
} else {// 其他情况-没有上级 没有下级
|
|
|
|
|
obj.type = NODE_TYPE.ALONE;
|
2026-02-27 11:43:27 +08:00
|
|
|
}
|
|
|
|
|
return obj
|
|
|
|
|
})
|
|
|
|
|
})
|
2026-02-26 11:45:32 +08:00
|
|
|
|
|
|
|
|
this.edges = computed(() => {
|
|
|
|
|
const arr = []
|
|
|
|
|
this.nodes.value.forEach((node, index) => {
|
2026-03-03 15:39:54 +08:00
|
|
|
const superiorID = node.data.superiorID;
|
|
|
|
|
const isSuperior = this.nodes.value.some((v) => v.id === superiorID)
|
|
|
|
|
if (superiorID && isSuperior) {
|
|
|
|
|
const source = node.data.superiorID
|
|
|
|
|
const target = node.id
|
2026-02-26 11:45:32 +08:00
|
|
|
arr.push({
|
2026-03-03 15:39:54 +08:00
|
|
|
id: `el-${source}-${target}`,
|
|
|
|
|
source: source,
|
2026-02-26 11:45:32 +08:00
|
|
|
target: target,
|
2026-03-02 16:24:32 +08:00
|
|
|
selectable: false,
|
2026-03-12 17:07:04 +08:00
|
|
|
visible: (node.data.type !== NODE_DATATYPE.RESULT_IMAGE || node.data.isActive),
|
2026-03-02 13:51:14 +08:00
|
|
|
type: 'default'
|
2026-02-26 11:45:32 +08:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return arr
|
|
|
|
|
})
|
2026-03-12 17:07:04 +08:00
|
|
|
window.nodes = this.nodes
|
2026-02-26 11:45:32 +08:00
|
|
|
|
|
|
|
|
}
|
2026-03-05 13:46:10 +08:00
|
|
|
/** 设置激活节点 */
|
|
|
|
|
setActiveNodeID(id: string) { this.activeNodeID.value = id }
|
2026-02-27 14:58:36 +08:00
|
|
|
/** 添加节点 */
|
|
|
|
|
addNode(node: NodesItem) {
|
2026-03-05 10:18:10 +08:00
|
|
|
this.nodes.value.push(node);
|
|
|
|
|
this.recordState()
|
2026-02-27 14:58:36 +08:00
|
|
|
}
|
|
|
|
|
/** 删除节点 */
|
2026-03-05 15:59:04 +08:00
|
|
|
async deleteNode(id: string, { isElMessageBox } = { isElMessageBox: false }) {
|
2026-03-05 16:56:03 +08:00
|
|
|
const node = this.getNodeById(id)
|
|
|
|
|
if (!node) return console.warn(`没有找到指定id:${id}`)
|
|
|
|
|
if (node.data.disableDelete) return console.warn('该节点禁用删除')
|
2026-03-05 15:59:04 +08:00
|
|
|
let deletePromise: any = true
|
|
|
|
|
if (isElMessageBox) {
|
2026-03-05 15:13:16 +08:00
|
|
|
deletePromise = await new Promise<void>((resolve, reject) => {
|
|
|
|
|
ElMessageBox.confirm(
|
2026-03-05 15:59:04 +08:00
|
|
|
t('flowCanvas.deleteCardConfirm'),
|
2026-03-05 15:13:16 +08:00
|
|
|
'',
|
|
|
|
|
{
|
2026-03-05 15:59:04 +08:00
|
|
|
confirmButtonText: t('flowCanvas.confirm'),
|
|
|
|
|
cancelButtonText: t('flowCanvas.cancel'),
|
2026-03-05 15:13:16 +08:00
|
|
|
}
|
|
|
|
|
).then(() => {
|
|
|
|
|
resolve(true)
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
resolve(false)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
if (!deletePromise) return console.log('删除操作被取消')
|
2026-02-27 14:58:36 +08:00
|
|
|
this.nodes.value = this.nodes.value.filter((node: NodesItem) => node.id !== id)
|
2026-03-05 10:18:10 +08:00
|
|
|
this.recordState()
|
2026-02-27 14:58:36 +08:00
|
|
|
}
|
2026-03-03 16:16:30 +08:00
|
|
|
/** 获取节点 */
|
2026-03-05 10:18:10 +08:00
|
|
|
getNodeById(id: string) { return this.nodes.value.find((node: NodesItem) => node.id === id) }
|
2026-03-03 16:16:30 +08:00
|
|
|
/** 获取下级节点 */
|
2026-03-05 10:18:10 +08:00
|
|
|
getSubordNodeByID(id: string) { return this.nodes.value.find((node: NodesItem) => node.data.superiorID === id) }
|
2026-03-12 17:07:04 +08:00
|
|
|
getLastNode() { console.log(this.nodes.value); return this.nodes.value[this.nodes.value.length - 1] }
|
2026-03-04 15:06:22 +08:00
|
|
|
/** 设置工具 */
|
2026-03-05 10:18:10 +08:00
|
|
|
setTool(tool: string) { this.tool.value = tool }
|
2026-03-04 15:06:22 +08:00
|
|
|
/** 设置光标 */
|
|
|
|
|
setCursor(v: string) { this.cursor.value = v }
|
|
|
|
|
/** 设置节点是否可拖动 */
|
|
|
|
|
setNodesDraggable(v: boolean) { this.nodesDraggable.value = v }
|
|
|
|
|
/** 设置是否可以平移画布 */
|
|
|
|
|
setPanOnDrag(v: boolean) { this.panOnDrag.value = v }
|
2026-03-05 10:27:41 +08:00
|
|
|
/** 设置节点层级至最顶部 */
|
|
|
|
|
bringToFont(id) {
|
|
|
|
|
const fromIndex = this.nodes.value.findIndex(item => item.id === id)
|
|
|
|
|
if (fromIndex === -1) return console.warn(`没有找到指定id:${id}`)
|
|
|
|
|
this.nodes.value.splice(this.nodes.value.length - 1, 0, ...this.nodes.value.splice(fromIndex, 1))
|
2026-03-04 15:40:30 +08:00
|
|
|
}
|
2026-03-05 10:27:41 +08:00
|
|
|
/** 设置节点层级至最低部 */
|
|
|
|
|
sendToBack(id) {
|
|
|
|
|
const fromIndex = this.nodes.value.findIndex(item => item.id === id)
|
|
|
|
|
if (fromIndex === -1) return console.warn(`没有找到指定id:${id}`)
|
|
|
|
|
this.nodes.value.splice(0, 0, ...this.nodes.value.splice(fromIndex, 1))
|
|
|
|
|
}
|
2026-03-05 10:18:10 +08:00
|
|
|
/** 记录状态 */
|
|
|
|
|
recordState() {
|
|
|
|
|
if (this.historyIndex.value < this.historyList.value.length - 1) {
|
2026-03-05 14:34:41 +08:00
|
|
|
this.historyList.value.splice(this.historyIndex.value + 1)
|
2026-03-05 10:18:10 +08:00
|
|
|
}
|
|
|
|
|
const state = {
|
|
|
|
|
nodes: JSON.stringify(this.nodes.value)
|
2026-03-05 10:27:41 +08:00
|
|
|
}
|
2026-03-05 10:18:10 +08:00
|
|
|
this.historyList.value.push(state)
|
|
|
|
|
const size = this.historyList.value.length - this.mxHistory.value
|
|
|
|
|
if (size > 0) this.historyList.value.splice(0, size)
|
|
|
|
|
this.historyIndex.value = this.historyList.value.length - 1
|
2026-03-04 15:40:30 +08:00
|
|
|
}
|
2026-03-05 10:18:10 +08:00
|
|
|
/** 撤回状态 */
|
|
|
|
|
undoState() {
|
|
|
|
|
var index = this.historyIndex.value - 1
|
|
|
|
|
const state = this.historyList.value[index]
|
|
|
|
|
if (!state) return
|
|
|
|
|
this.historyIndex.value = index
|
|
|
|
|
this.nodes.value = JSON.parse(state.nodes)
|
2026-03-04 15:40:30 +08:00
|
|
|
}
|
2026-03-05 10:18:10 +08:00
|
|
|
/** 重做状态 */
|
|
|
|
|
redoState() {
|
|
|
|
|
var index = this.historyIndex.value + 1
|
|
|
|
|
const state = this.historyList.value[index]
|
|
|
|
|
if (!state) return
|
|
|
|
|
this.historyIndex.value = index
|
|
|
|
|
this.nodes.value = JSON.parse(state.nodes)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-12 17:07:04 +08:00
|
|
|
/** 显示指定子节点和父节点连接线,隐藏父节点和其他子节点链接线, */
|
|
|
|
|
showNodeConnections(id: string) {
|
|
|
|
|
const node = this.getNodeById(id)
|
|
|
|
|
if(node.data.component != NODE_DATATYPE.RESULT_IMAGE && node.data.superiorID) return
|
|
|
|
|
let edges_ = JSON.parse(JSON.stringify(this.edges.value))
|
|
|
|
|
this.nodes.value.forEach((nodeItem) => {
|
|
|
|
|
if(node.data.superiorID === nodeItem.data.superiorID && nodeItem.id == id) {
|
|
|
|
|
nodeItem.data.isActive = true
|
|
|
|
|
}else if(node.data.superiorID == nodeItem.data.superiorID){
|
|
|
|
|
nodeItem.data.isActive = false
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-11 17:02:32 +08:00
|
|
|
dispose() {
|
|
|
|
|
this.historyList.value = []
|
|
|
|
|
this.historyIndex.value = 0
|
|
|
|
|
}
|
2026-02-26 11:45:32 +08:00
|
|
|
}
|