346 lines
11 KiB
TypeScript
346 lines
11 KiB
TypeScript
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
|
||
}
|
||
}
|