@@ -36,6 +36,7 @@ import { ref, reactive, nextTick, computed } from 'vue'
3636import { canvasState, getConfigure, getController, getCurrent, copyNode, removeNodeById } from '../container'
3737import { useLayout, useModal, useCanvas, usePage, getMergeMeta } from '@opentiny/tiny-engine-meta-register'
3838import { iconRight } from '@opentiny/vue-icon'
39+ import { useMultiSelect } from '../composables/useMultiSelect'
3940
4041const menuState = reactive({
4142 position: null,
@@ -47,6 +48,9 @@ const current = ref(null)
4748const menuDom = ref(null)
4849const subMenuStyles = ref(null)
4950
51+ // 子菜单宽度常量
52+ const SUB_MENU_WIDTH = 137
53+
5054export const closeMenu = () => {
5155 menuState.show = false
5256 current.value = null
@@ -69,11 +73,11 @@ export const openMenu = (event) => {
6973 if (right > canvasRect.right) {
7074 menuState.position.left = `${parseInt(menuState.position.left) - width - 2}px`
7175 }
72- // sub-menu样式width为100px,少于100宽度的空白区域则放置到左侧
73- if (right + 100 < canvasRect.right) {
74- subMenuStyles.value = { right: '-100px' }
76+ // sub-menu样式width为 137 px,少于 137 宽度的空白区域则放置到左侧
77+ if (right + SUB_MENU_WIDTH < canvasRect.right) {
78+ subMenuStyles.value = { right: `-${SUB_MENU_WIDTH}px`, width: `${SUB_MENU_WIDTH}px` }
7579 } else {
76- subMenuStyles.value = { left: '-100px' }
80+ subMenuStyles.value = { left: `-${SUB_MENU_WIDTH}px`, width: `${SUB_MENU_WIDTH}px` }
7781 }
7882 }
7983 })
@@ -84,6 +88,8 @@ export default {
8488 IconRight: iconRight()
8589 },
8690 setup(props, { emit }) {
91+ const { multiSelectedStates, areSiblingNodes, batchAddParent, groupAddParent } = useMultiSelect()
92+
8793 const menus = ref([
8894 { name: '修改属性', code: 'config' },
8995 {
@@ -116,10 +122,40 @@ export default {
116122 { name: '绑定事件', code: 'bindEvent' }
117123 ])
118124
125+ // 多选菜单
126+ const multiSelectMenus = ref([
127+ { name: '删除', code: 'multiDel' },
128+ { name: '复制', code: 'multiCopy' },
129+ {
130+ name: '添加父级',
131+ items: [
132+ {
133+ name: '容器(批量)',
134+ code: 'batchWrap',
135+ value: 'div'
136+ },
137+ {
138+ name: '容器(公共父级)',
139+ code: 'groupWrap',
140+ value: 'div',
141+ check: () => areSiblingNodes()
142+ },
143+ {
144+ name: '弹出框(公共父级)',
145+ code: 'groupWrap',
146+ value: 'TinyPopover',
147+ check: () => areSiblingNodes()
148+ }
149+ ],
150+ code: 'multiAddParent'
151+ }
152+ ])
153+
119154 // 通过画布右键快捷新建区块
120155 const { SaveNewBlock } = getMergeMeta('engine.plugins.blockmanage')?.components || {}
121156 if (SaveNewBlock) {
122157 menus.value.push({ name: '新建区块', code: 'createBlock' })
158+ multiSelectMenus.value.push({ name: '新建区块', code: 'createBlock' })
123159 }
124160
125161 menus.value.unshift({
@@ -132,14 +168,26 @@ export default {
132168 }
133169 })
134170
135- const filteredMenus = computed(() =>
136- menus.value.filter((item) => {
171+ const isMultiSelect = computed(() => multiSelectedStates.value.length > 1)
172+
173+ const filteredMenus = computed(() => {
174+ // 如果是多选,则展示多选菜单
175+ if (isMultiSelect.value) {
176+ return multiSelectMenus.value.filter((item) => {
177+ if (typeof item.show === 'function') {
178+ return item.show()
179+ }
180+ return true
181+ })
182+ }
183+
184+ return menus.value.filter((item) => {
137185 if (typeof item.show === 'function') {
138186 return item.show()
139187 }
140188 return true
141189 })
142- )
190+ } )
143191
144192 const boxVisibility = ref(false)
145193
@@ -154,6 +202,16 @@ export default {
154202 copy() {
155203 copyNode(getCurrent().schema?.id)
156204 },
205+ multiDel() {
206+ const ids = multiSelectedStates.value.map((state) => state.id)
207+ ids.forEach((id) => removeNodeById(id))
208+ },
209+ multiCopy() {
210+ const ids = multiSelectedStates.value.map((state) => state.id)
211+ ids.forEach((id) => copyNode(id))
212+
213+ useCanvas().canvasApi.value.updateRect?.()
214+ },
157215 config() {
158216 activeSetting(PLUGIN_NAME.Props)
159217 },
@@ -218,6 +276,14 @@ export default {
218276 parent.children.splice(index, 1, wrapSchema)
219277 getController().addHistory()
220278 },
279+ // 处理批量添加父级的操作
280+ batchWrap({ value }) {
281+ batchAddParent(value)
282+ },
283+ // 处理整体添加父级的操作
284+ groupWrap({ value }) {
285+ groupAddParent(value)
286+ },
221287 createBlock() {
222288 if (useCanvas().isSaved()) {
223289 boxVisibility.value = true
@@ -240,8 +306,13 @@ export default {
240306 return true
241307 }
242308
243- const actions = ['del', 'copy', 'addParent']
244- return actions.includes(actionItem.code) && !getCurrent().schema?.id
309+ if (isMultiSelect.value) {
310+ const multiSelectActions = ['multiDel', 'multiCopy', 'multiAddParent']
311+ return multiSelectActions.includes(actionItem.code) && multiSelectedStates.value.length === 0
312+ } else {
313+ const actions = ['del', 'copy', 'addParent']
314+ return actions.includes(actionItem.code) && !getCurrent().schema?.id
315+ }
245316 }
246317
247318 const onShowChildrenMenu = (menuItem) => {
@@ -326,7 +397,6 @@ export default {
326397 }
327398 }
328399 & .sub-menu {
329- width : 100px ;
330400 position : absolute ;
331401 top : -2px ;
332402 }
0 commit comments