diff --git a/src/App.vue b/src/App.vue index b5d00f1..870be6c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -123,6 +123,21 @@ watch( } ); +const handleDropOnCanvas = (event: DragEvent) => { + event.preventDefault(); + const nodeData = JSON.parse(event.dataTransfer?.getData('application/json') || '{}'); + // 计算画布坐标(这里简单用鼠标坐标,后续可结合 LogicFlow 视口变换优化) + const rect = (event.target as HTMLElement).getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = event.clientY - rect.top; + const id = `node-${Date.now()}-${Math.floor(Math.random() * 10000)}`; + filesStore.addNode({ id, type: nodeData.type, x, y, ...nodeData.data }); +}; + +const handleDragOverOnCanvas = (event: DragEvent) => { + event.preventDefault(); +}; + \ No newline at end of file diff --git a/src/components/flow/FlowEditor.vue b/src/components/flow/FlowEditor.vue index 2e2ab1a..68672d9 100644 --- a/src/components/flow/FlowEditor.vue +++ b/src/components/flow/FlowEditor.vue @@ -1,102 +1,151 @@ \ No newline at end of file diff --git a/src/components/flow/nodes/yys/PropertySelectNode.vue b/src/components/flow/nodes/yys/PropertySelectNode.vue index 3226ea9..8df4972 100644 --- a/src/components/flow/nodes/yys/PropertySelectNode.vue +++ b/src/components/flow/nodes/yys/PropertySelectNode.vue @@ -1,83 +1,31 @@ @@ -258,7 +79,6 @@ defineExpose({ min-width: 180px; min-height: 180px; } - .node-content { position: relative; background-color: white; @@ -266,89 +86,28 @@ defineExpose({ border-radius: 4px; padding: 0; cursor: pointer; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); width: 100%; height: 100%; - min-width: 180px; min-height: 180px; } - -:deep(.vue-flow__node-resizer) { - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - pointer-events: none; -} - -:deep(.vue-flow__node-resizer-handle) { - position: absolute; - width: 8px; - height: 8px; - background-color: #409EFF; - border: 1px solid white; - border-radius: 50%; - pointer-events: all; -} - -:deep(.vue-flow__node-resizer-handle.top-left) { - top: -4px; - left: -4px; - cursor: nwse-resize; -} - -:deep(.vue-flow__node-resizer-handle.top-right) { - top: -4px; - right: -4px; - cursor: nesw-resize; -} - -:deep(.vue-flow__node-resizer-handle.bottom-left) { - bottom: -4px; - left: -4px; - cursor: nesw-resize; -} - -:deep(.vue-flow__node-resizer-handle.bottom-right) { - bottom: -4px; - right: -4px; - cursor: nwse-resize; -} - -.priority-required { - border: 2px solid #f56c6c; -} - -.priority-recommended { - border: 2px solid #67c23a; -} - -.priority-optional { - border: 1px solid #dcdfe6; -} - .node-header { padding: 8px 10px; background-color: #f0f7ff; border-bottom: 1px solid #dcdfe6; border-radius: 4px 4px 0 0; } - .node-title { font-weight: bold; font-size: 14px; } - .node-body { padding: 10px; display: flex; flex-direction: column; align-items: center; } - .property-main { display: flex; flex-direction: column; @@ -356,20 +115,17 @@ defineExpose({ width: 100%; margin-bottom: 8px; } - .property-type { font-size: 16px; font-weight: bold; margin-bottom: 5px; } - .property-value { font-size: 16px; color: #409eff; font-weight: bold; margin-bottom: 5px; } - .property-placeholder { width: 120px; height: 40px; @@ -383,29 +139,16 @@ defineExpose({ margin: 8px 0; transition: width 0.2s, height 0.2s; } - .property-details { width: 100%; border-top: 1px dashed #ebeef5; padding-top: 8px; } - .property-priority { font-size: 12px; color: #606266; margin-bottom: 5px; } - -.property-extra-info { - font-size: 11px; - color: #909399; - margin-bottom: 5px; -} - -.property-extra-info > div { - margin-bottom: 2px; -} - .property-description { font-size: 11px; color: #606266; @@ -414,4 +157,4 @@ defineExpose({ padding-top: 5px; word-break: break-all; } - \ No newline at end of file + \ No newline at end of file diff --git a/src/components/flow/nodes/yys/ShikigamiSelectNode.vue b/src/components/flow/nodes/yys/ShikigamiSelectNode.vue index 7321c86..8bbf590 100644 --- a/src/components/flow/nodes/yys/ShikigamiSelectNode.vue +++ b/src/components/flow/nodes/yys/ShikigamiSelectNode.vue @@ -1,130 +1,71 @@ \ No newline at end of file diff --git a/src/components/flow/nodes/yys/YuhunSelectNode.vue b/src/components/flow/nodes/yys/YuhunSelectNode.vue index 56e8772..5f595fc 100644 --- a/src/components/flow/nodes/yys/YuhunSelectNode.vue +++ b/src/components/flow/nodes/yys/YuhunSelectNode.vue @@ -1,163 +1,68 @@ diff --git a/src/ts/useStore.ts b/src/ts/useStore.ts index 16a9176..41d1a9c 100644 --- a/src/ts/useStore.ts +++ b/src/ts/useStore.ts @@ -6,6 +6,12 @@ import { useGlobalMessage } from "./useGlobalMessage"; const { showMessage } = useGlobalMessage(); +// LogicFlow 实例全局引用 +let logicFlowInstance: any = null; +function setLogicFlowInstance(lf: any) { + logicFlowInstance = lf; +} + function getDefaultState() { return { fileList: [ @@ -36,6 +42,69 @@ function getDefaultState() { x: 350, y: 120, text: "File1-圆形节点" + }, + { + id: "node-3", + type: "shikigamiSelect", + x: 200, + y: 300, + properties: { + shikigami: { + name: "时曜泷夜叉姬", + avatar: "/assets/Shikigami/sp/584.png", + rarity: "SP" + }, + width: 100, + height: 80 + } + }, + { + id: "node-yuhun-1", + type: "yuhunSelect", + x: 300, + y: 200, + properties: { + yuhun: { + name: "针女", + avatar: "/assets/Yuhun/针女.png", + type: "攻击类" + }, + width: 100, + height: 80 + } + }, + { + id: "node-property-1", + type: "propertySelect", + x: 500, + y: 300, + properties: { + property: { + type: "attack", + priority: "required", + attackType: "fixed", + attackValue: 3000, + description: "主输出式神,需高攻击", + levelRequired: "40", + skillRequiredMode: "all", + skillRequired: ["5", "5", "5"], + yuhun: { + yuhunSetEffect: [ + { name: "破势", avatar: "/assets/Yuhun/破势.png" }, + { name: "荒骷髅", avatar: "/assets/Yuhun/荒骷髅.png" } + ], + target: "1", + property2: ["Attack"], + property4: ["Attack"], + property6: ["Crit", "CritDamage"] + }, + expectedDamage: 10000, + survivalRate: 50, + damageType: "balanced" + }, + width: 120, + height: 100 + } } ], edges: [ @@ -130,13 +199,26 @@ interface FileGroup { details: string; } +interface LogicFlowNode { + id: string; + type: string; + x: number; + y: number; + text?: string | object; + properties?: Record; +} + interface FlowFile { label: string; name: string; visible: boolean; type: string; groups: FileGroup[]; - flowData?: any; + flowData?: { + nodes: LogicFlowNode[]; + edges: any[]; + viewport: any; + }; } export const useFilesStore = defineStore('files', () => { @@ -190,7 +272,7 @@ export const useFilesStore = defineStore('files', () => { }; // 添加节点 - const addNode = (node: Node) => { + const addNode = (node: LogicFlowNode) => { const file = fileList.value.find(f => f.name === activeFile.value); if (!file) return; if (!file.flowData) file.flowData = { nodes: [], edges: [], viewport: { x: 0, y: 0, zoom: 1 } }; @@ -198,15 +280,26 @@ export const useFilesStore = defineStore('files', () => { }; // 更新节点 - const updateNode = (nodeId: string, updateData: Partial) => { + const updateNode = (nodeId: string, updateData: Partial) => { const file = fileList.value.find(f => f.name === activeFile.value); if (!file || !file.flowData || !file.flowData.nodes) return; - const nodeIndex = file.flowData.nodes.findIndex(n => n.id === nodeId); + const nodeIndex = file.flowData.nodes.findIndex((n: LogicFlowNode) => n.id === nodeId); if (nodeIndex === -1) return; - file.flowData.nodes[nodeIndex] = { - ...file.flowData.nodes[nodeIndex], - ...updateData, - }; + + const oldNode = file.flowData.nodes[nodeIndex]; + const mergedNode = { ...oldNode, ...updateData }; + + // Deep merge properties + if (updateData.properties && oldNode.properties) { + mergedNode.properties = { ...oldNode.properties, ...updateData.properties }; + } + file.flowData.nodes[nodeIndex] = mergedNode; + + // 同步 LogicFlow 画布 + if (logicFlowInstance && mergedNode.properties) { + // setProperties overwrites, so we pass the fully merged properties object + logicFlowInstance.setProperties(nodeId, mergedNode.properties); + } }; // 删除节点 @@ -239,14 +332,15 @@ export const useFilesStore = defineStore('files', () => { const updateNodePosition = (nodeId: string, position: { x: number; y: number }) => { const file = fileList.value.find(f => f.name === activeFile.value); if (!file || !file.flowData || !file.flowData.nodes) return; - const node = file.flowData.nodes.find(n => n.id === nodeId); + const node = file.flowData.nodes.find((n: LogicFlowNode) => n.id === nodeId); if (node) { - node.position = position; + node.x = position.x; + node.y = position.y; } }; // 更新节点顺序 - const updateNodesOrder = (nodes: Node[]) => { + const updateNodesOrder = (nodes: LogicFlowNode[]) => { const file = fileList.value.find(f => f.name === activeFile.value); if (!file || !file.flowData) return; file.flowData.nodes = nodes; @@ -422,5 +516,6 @@ export const useFilesStore = defineStore('files', () => { setupAutoSave, exportData, importData, + setLogicFlowInstance, }; }); \ No newline at end of file