Files
FiDA_Front/src/components/Canvas/FlowCanvas/manager/StateManager.ts
2026-04-20 11:10:58 +08:00

346 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ref, computed } from "vue";
import { NODE_TYPE, NODE_DATATYPE } from '../tools/index.d'
import { ElMessageBox } from 'element-plus'
import i18n from '@/lang'
import { putSketchFlowCanvas } from '@/api/flow-canvas'
import myEvent from '@/utils/myEvent'
import { updateVersionSketchUrlApi } from '@/api/flow-canvas'
const t = i18n.global.t
//推送到对话框的助手
const chatAssistant = {
[NODE_DATATYPE.TO_REAL_STYLE]:{
content: t('FlowCanvas.toRealStyleDesignAssistant'),
nodeType:NODE_DATATYPE.TO_REAL_STYLE,
},
[NODE_DATATYPE.CANVAS_MODE]:{
content: t('FlowCanvas.surfaceEditCanvasDesignAssistant'),
nodeType:NODE_DATATYPE.CANVAS_MODE,
},
[NODE_DATATYPE.Fast_MODE]:{
content: t('FlowCanvas.surfaceEditAIDesignAssistant'),
nodeType:NODE_DATATYPE.Fast_MODE,
},
[NODE_DATATYPE.COLOR_PALETTE]:{
content: t('FlowCanvas.colorPaletteDesignAssistant'),
nodeType:NODE_DATATYPE.COLOR_PALETTE,
},
[NODE_DATATYPE.SCENE_COMPOSITION]:{
content: t('FlowCanvas.sceneCompositionDesignAssistant'),
nodeType:NODE_DATATYPE.SCENE_COMPOSITION,
},
[NODE_DATATYPE.TO_3D_MODEL]:{
content: t('FlowCanvas.threeModelDesignAssistant'),
nodeType:NODE_DATATYPE.TO_3D_MODEL,
},
[NODE_DATATYPE.TO_REAL_VARIANTS]:{
content: t('FlowCanvas.toRealVariantsDesignAssistant'),
nodeType:NODE_DATATYPE.TO_3D_MODEL,
},
[NODE_DATATYPE.TO_3VIEW]:{
content: t('FlowCanvas.to3DViewDesignAssistant'),
nodeType:NODE_DATATYPE.TO_3VIEW,
},
}
export interface NodesItem {
id: string
type: string
class: string
position: { x: number, y: number }
data: { component: any, type: string, superiorID?: string }
}
export class StateManager {
vueFlow: any
activeNodeID: any
nodes: any
nodes_: any
edges: any
zoom: any
tool: any
cursor: any
// 节点是否可拖动
nodesDraggable: any
// 拖动时是否可以平移画布
panOnDrag: any
// 历史记录-撤回/重做
mxHistory: any
historyList: any
historyIndex: any
// 管理器
eventManager: any
flowManager: any
nodeManager: any
toolManager: any
generateManager: any
// 保存画布数据定时器
saveCanvasTime: any
// 保存画布数据定时器时间间隔
saveCanvasTimeInterval: any
// 打开画布线稿id
sketchId: any
// 设置管理器
setManager(options) {
options.eventManager && (this.eventManager = options.eventManager)
options.flowManager && (this.flowManager = options.flowManager)
options.nodeManager && (this.nodeManager = options.nodeManager)
options.toolManager && (this.toolManager = options.toolManager)
options.generateManager && (this.generateManager = options.generateManager)
}
constructor(options) {
this.vueFlow = options.vueFlow
this.zoom = ref(1)
this.tool = ref("")
this.cursor = ref("")
this.nodesDraggable = ref(false)
this.panOnDrag = ref(false)
this.mxHistory = ref(50)
this.historyList = ref([])
this.historyIndex = ref(0)
this.sketchId = ref(options.sketchId)
this.saveCanvasTimeInterval = 6000
this.saveCanvasTime = null
this.activeNodeID = ref("")
this.nodes = ref<NodesItem[]>([]);
this.nodes_ = computed(() => {
return this.nodes.value.map((node, index) => {
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)
if (!isSuperior && isSubord) {// 没有上级 有下级
obj.type = NODE_TYPE.INPUT;
} else if (isSuperior && isSubord) {// 有上级 有下级
obj.type = NODE_TYPE.SECONDARY;
} else if (isSuperior && !isSubord) {// 有上级 没有下级
obj.type = NODE_TYPE.OUTPUT;
} else {// 其他情况-没有上级 没有下级
obj.type = NODE_TYPE.ALONE;
}
return obj
})
})
this.edges = computed(() => {
const arr = []
this.nodes.value.forEach((node, index) => {
const superiorID = node.data.superiorID;
const isSuperior = this.nodes.value.some((v) => v.id === superiorID)
if (isSuperior) {
const source = node.data.superiorID
const target = node.id
arr.push({
id: `el-${source}-${target}`,
source: source,
target: target,
selectable: false,
visible: (node.data.type == NODE_DATATYPE.RESULT_IMAGE && node.data.isActive) || node.data.type !== NODE_DATATYPE.RESULT_IMAGE,
type: 'default'
})
}
})
return arr
})
}
/** 设置激活节点 */
setActiveNodeID(id: string) { this.activeNodeID.value = id;this.showNodeConnections(id) }
/** 添加节点 */
addNode(node: NodesItem) {
this.nodes.value.push(node);
this.recordState()
this.exportFlow()
if(chatAssistant[node.data.type])myEvent.emit('assistantPushChat',chatAssistant[node.data.type])
}
/** 删除节点 */
async deleteNode(id: string) {
this.nodes.value = this.nodes.value.filter((node: NodesItem) => node.id !== id)
}
/** 获取初始节点 */
getInitialNode() { return this.nodes.value.find((node: NodesItem) => node?.data?.versionImgUpdataList) }
/** 获取节点 */
getNodeById(id: string) { return this.nodes.value.find((node: NodesItem) => node.id === id) }
/** 获取下级节点 */
getSubordNodeById(id: string) { return this.nodes.value.find((node: NodesItem) => node.data.superiorID === id) }
getLastNode() { return this.nodes.value[this.nodes.value.length - 1] }
/** 获取上级生成节点的图片 */
getSuperiorNodeImage(superiorID: string) {
const superiorNode = this.getNodeById(superiorID)
if(!superiorNode){
// ElMessage.error(t('FlowCanvas.cannotFindSuperiorImage'))
return null
}
const superiorNodeUrl = superiorNode.data.data.imageProcessTasks.filter((item)=>{
return item.taskId == superiorNode.data.data.selectTaskId
})[0]?.url
return superiorNodeUrl
}
/** 获取下级所有子级节点 */
async deleteSubordinateAllNodes(id: string,{ isElMessageBox } = { isElMessageBox: false }) {
const node = this.getNodeById(id)
if (!node) return console.warn(`没有找到指定id:${id}`)
if (node.data.disableDelete) return ElMessage.error(t('FlowCanvas.initialNodeProhibited'))
const result = [node]
const deleteVersionImgUpdataList = []
node.data.data?.imageProcessTasks?.forEach((item) =>{
deleteVersionImgUpdataList.push(item.url)
})
const findChildren = (parentId: string) => {
const children = this.nodes.value.filter(item => item.data.superiorID === parentId)
children.forEach(child => {
if(child.data.type !== NODE_DATATYPE.RESULT_IMAGE){
result.push(child)
console.log(child)
child.data.data?.imageProcessTasks?.forEach((item) =>{
deleteVersionImgUpdataList.push(item.url)
})
}
findChildren(child.id)
})
}
findChildren(id)
let deletePromise: any = true
if (isElMessageBox) {
deletePromise = await new Promise<void>((resolve, reject) => {
ElMessageBox.confirm(
result.length > 1 ? t('FlowCanvas.deleteSubordinateCard') : t('FlowCanvas.deleteCardConfirm'),
'',
{
confirmButtonText: t('FlowCanvas.confirm'),
cancelButtonText: t('FlowCanvas.cancel'),
}
).then(() => {resolve(true)
}).catch(() => {
resolve(false)
})
})
}
if(!deletePromise) return console.log('删除操作被取消')
// 删除如果是最后一张图需要更新版本图url
let initialNode = this.getInitialNode()
let updataListIndex
let isUpdataEndUrl = false
deleteVersionImgUpdataList?.forEach((item) => {
updataListIndex = initialNode.data.versionImgUpdataList.indexOf(item)
if(updataListIndex == (initialNode.data.versionImgUpdataList.length - 1))isUpdataEndUrl = true
if(initialNode.data.versionImgUpdataList.length > 1)initialNode.data.versionImgUpdataList = initialNode.data.versionImgUpdataList.filter((v) => v !== item)
})
if(isUpdataEndUrl){
updateVersionSketchUrlApi({
sketchId: this.sketchId.value,
newUrl: initialNode.data.versionImgUpdataList[initialNode.data.versionImgUpdataList.length - 1],
})
}
if(node.data.data?.imageProcessTasks?.length > 1){
node.data.data.imageProcessTasks = node.data.data.imageProcessTasks.filter((item) => item.taskId !== node.data.data.selectTaskId)
return
}
this.deleteNode(id)
result.forEach(item => {
this.deleteNode(item.id)
})
this.recordState()
this.exportFlow()
}
/** 设置工具 */
setTool(tool: string) { this.tool.value = tool }
/** 设置光标 */
setCursor(v: string) { this.cursor.value = v }
/** 设置节点是否可拖动 */
setNodesDraggable(v: boolean) { this.nodesDraggable.value = v }
/** 设置是否可以平移画布 */
setPanOnDrag(v: boolean) { this.panOnDrag.value = v }
/** 获取所有下级节点 */
getSubordNodes(id: string) { return this.nodes.value.filter((node: NodesItem) => node.data.superiorID === id) }
/** 设置节点层级至最顶部 */
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))
}
/** 设置节点层级至最低部 */
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))
}
/** 记录状态 */
recordState() {
if (this.historyIndex.value < this.historyList.value.length - 1) {
this.historyList.value.splice(this.historyIndex.value + 1)
}
const state = {
nodes: JSON.stringify(this.nodes.value)
}
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
}
/** 画布数据存储 */
async exportFlow (time:number = 0,loading:boolean = false){
if(!this.sketchId.value)return
clearTimeout(this.saveCanvasTime)
await new Promise((resolve) => {
this.saveCanvasTime = setTimeout(()=>{
putSketchFlowCanvas({
id: this.sketchId.value,
canvasData: JSON.stringify(this.nodes.value) }).then(() => {
resolve(true)
},loading).catch(() => {
resolve(true)
})
},time)
})
}
/** 撤回状态 */
undoState() {
const 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)
this.exportFlow(this.saveCanvasTimeInterval)
}
/** 重做状态 */
redoState() {
const 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)
this.exportFlow(this.saveCanvasTimeInterval)
}
/** 显示指定子节点和父节点连接线,隐藏父节点和其他子节点链接线, */
showNodeConnections(id: string) {
if(!id) return
const node = this.getNodeById(id)
if(!node?.data?.superiorID) return
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
}
})
}
dispose() {
clearTimeout(this.saveCanvasTime)
this.historyList.value = []
this.historyIndex.value = 0
}
}