11import { ref } from 'vue'
2- import { useCanvas } from '@opentiny/tiny-engine-meta-register'
2+ import { useCanvas , useMessage , useHistory } from '@opentiny/tiny-engine-meta-register'
33import { utils } from '@opentiny/tiny-engine-utils'
4- import { getDocument , getRect , querySelectById , POSITION , insertNode } from '../container'
5-
6- interface Schema {
7- id : string | null
8- componentName : string
9- props ?: Record < string , any >
10- children ?: Schema [ ]
11- parent ?: {
12- id : string
13- children : Schema [ ]
14- }
15- }
4+ import { getDocument , getRect , querySelectById , POSITION , insertNode , selectNode } from '../container'
5+ import type { Node } from '../../../types'
166
177interface SelectionState {
188 id : string
199 top ?: number
2010 left ?: number
2111 width ?: number
2212 height ?: number
23- schema ?: Schema
13+ schema ?: any
2414 parent ?: {
2515 id : string
26- children : Schema [ ]
16+ children : Node [ ]
2717 }
2818}
2919
@@ -82,6 +72,19 @@ export const useMultiSelect = () => {
8272 multiSelectedStates . value = [ ]
8373 }
8474
75+ /**
76+ * 获取选中节点在父节点children中的索引位置
77+ * @param {children } children 父节点的children
78+ * @param {string[] } selectedIds 选中的节点ID列表
79+ * @returns {number[] } 排序后的索引数组
80+ */
81+ const getSelectedNodeIndices = ( children : Node [ ] , selectedIds : string [ ] ) : number [ ] => {
82+ return selectedIds
83+ . map ( ( id ) => children . findIndex ( ( child : Node ) => child . id === id ) )
84+ . filter ( ( index ) => index !== - 1 )
85+ . sort ( ( a , b ) => a - b )
86+ }
87+
8588 /**
8689 * 判断选中的节点是否都是兄弟节点且是连续的
8790 * @returns {boolean } 如果所有选中节点都有相同的父节点且在父节点的children中是连续的,返回true;否则返回false
@@ -102,18 +105,12 @@ export const useMultiSelect = () => {
102105
103106 if ( nodesWithParent . some ( ( node ) => node . parent . id !== parentId ) ) return false
104107
105- const nodeIndices = multiSelectedStates . value
106- . map ( ( node ) => firstParent . children . findIndex ( ( child : Schema ) => child . id === node . id ) )
107- . sort ( ( a , b ) => a - b )
108+ // 获取并检查索引
109+ const selectedIds = multiSelectedStates . value . map ( ( state ) => state . id )
110+ const nodeIndices = getSelectedNodeIndices ( firstParent . children , selectedIds )
108111
109112 // 检查索引是否连续
110- for ( let i = 1 ; i < nodeIndices . length ; i ++ ) {
111- if ( nodeIndices [ i ] !== nodeIndices [ i - 1 ] + 1 ) {
112- return false
113- }
114- }
115-
116- return true
113+ return nodeIndices . every ( ( value , index ) => value === nodeIndices [ 0 ] + index )
117114 }
118115
119116 /**
@@ -138,36 +135,25 @@ export const useMultiSelect = () => {
138135 const selectedIds = multiSelectedStates . value . map ( ( state ) => state . id )
139136
140137 // 找出所有选中节点在父节点children中的索引位置
141- const indices = selectedIds
142- . map ( ( id ) => parent . children . findIndex ( ( child : Schema ) => child . id === id ) )
143- . sort ( ( a , b ) => a - b )
138+ const indices = getSelectedNodeIndices ( parent . children , selectedIds )
144139
145- // 检查索引是否连续
146- for ( let i = 1 ; i < indices . length ; i ++ ) {
147- if ( indices [ i ] !== indices [ i - 1 ] + 1 ) {
148- return false
149- }
150- }
140+ if ( indices . length === 0 ) return false
151141
152- // 记录最后一个节点和它的位置
153- const lastIndex = indices [ indices . length - 1 ]
154- const lastNode = parent . children [ lastIndex ]
142+ // 获取第一个和最后一个选中节点的索引
143+ const firstIndex = indices [ 0 ]
155144
156- // 从父节点中移除这些节点
157- const selectedNodes : Schema [ ] = [ ]
158- indices . reverse ( ) . forEach ( ( index ) => {
159- selectedNodes . unshift ( parent . children . splice ( index , 1 ) [ 0 ] )
160- } )
145+ // 复制选中的节点(不从原来的位置移除)
146+ const selectedNodes = indices . map ( ( index ) => parent . children [ index ] )
161147
162148 // 创建新的包装组件
163- const wrapSchema : Schema = {
149+ const wrapSchema : Node = {
164150 componentName,
165151 id : utils . guid ( ) ,
166152 props : { ...props } ,
167153 children : selectedNodes
168154 }
169155
170- // 特殊处理popover等组件
156+ // 特殊处理 TinyPopover 等组件
171157 if ( componentName === 'TinyPopover' ) {
172158 wrapSchema . props = {
173159 width : 200 ,
@@ -203,16 +189,23 @@ export const useMultiSelect = () => {
203189 ]
204190 }
205191
206- // 将包装组件插入到页面底部
207- insertNode (
208- {
209- node : lastNode ,
210- parent,
211- data : wrapSchema
212- } ,
213- POSITION . RIGHT
214- )
192+ // 从后向前删除原来的节点,避免索引变化
193+ for ( let i = indices . length - 1 ; i >= 0 ; i -- ) {
194+ parent . children . splice ( indices [ i ] , 1 )
195+ }
196+
197+ // 将新容器插入到第一个选中节点的位置
198+ parent . children . splice ( firstIndex , 0 , wrapSchema )
199+
200+ // 触发更新,重新选中节点
201+ useMessage ( ) . publish ( { topic : 'schemaChange' , data : { } } )
202+
203+ setTimeout ( ( ) => {
204+ useCanvas ( ) . setNode ( wrapSchema , parent )
205+ selectNode ( wrapSchema . id )
206+ } , 0 )
215207
208+ useHistory ( ) . addHistory ( )
216209 return true
217210 }
218211
@@ -223,8 +216,8 @@ export const useMultiSelect = () => {
223216 * @param {Schema } childSchema 子组件架构
224217 * @returns {Schema } 包装组件架构
225218 */
226- const createWrapperSchema = ( componentName : string , props : Record < string , any > = { } , childSchema : Schema ) : Schema => {
227- let wrapSchema : Schema = {
219+ const createWrapperSchema = ( componentName : string , props : Record < string , any > = { } , childSchema : Node ) : Node => {
220+ let wrapSchema : Node = {
228221 componentName,
229222 id : null ,
230223 props : {
0 commit comments