diff --git a/packages/controller/src/useLayout.js b/packages/controller/src/useLayout.js index fa08c375f5..841794b14b 100644 --- a/packages/controller/src/useLayout.js +++ b/packages/controller/src/useLayout.js @@ -42,7 +42,8 @@ const PLUGIN_POSITION = { leftBottom: 'leftBottom', independence: 'independence', rightTop: 'rightTop', - rightBottom: 'rightBottom' + rightBottom: 'rightBottom', + fixed: 'fixed' } const pluginState = reactive({ @@ -184,11 +185,15 @@ export default () => { //获取某个布局(左上/左下/右上)的插件名称列表 const getPluginsByLayout = (layout = 'all') => { - // 遍历对象并将 align 值分类到不同的数组中 - const targetLayout = Object.keys(pluginStorageReactive.value).filter( + // 筛选出符合布局条件的插件名称 + const pluginNames = Object.keys(pluginStorageReactive.value).filter( (key) => pluginStorageReactive.value[key].align === layout || layout === 'all' ) - return targetLayout //这里返回的是只有名字的数组 + + // 根据 index 对插件名称进行排序 + pluginNames.sort((a, b) => pluginStorageReactive.value[a].index - pluginStorageReactive.value[b].index) + + return pluginNames // 返回排序后的插件名称数组 } //修改某个插件的布局 @@ -198,6 +203,61 @@ export default () => { } } + //拖拽后改变插件位置 + const dragPluginLayout = (from, to, oldIndex, newIndex) => { + if (from === to && oldIndex === newIndex) return + + const items = Object.values(pluginStorageReactive.value) + // 记录拖拽项 + const movedItem = items.find((item) => item.align === from && item.index === oldIndex) + + // 同一列表中的拖拽 + if (from === to) { + if (oldIndex < newIndex) { + //往后移动 + items.forEach((item) => { + if (item !== movedItem && item.align === from && item.index > oldIndex && item.index <= newIndex) { + item.index -= 1 + } + }) + } else { + //往前移动 + items.forEach((item) => { + if (item !== movedItem && item.align === from && item.index >= newIndex && item.index < oldIndex) { + item.index += 1 + } + }) + } + } else { + // 跨列表拖拽 + items.forEach((item) => { + if (item !== movedItem && item.align === from && item.index > oldIndex) { + item.index -= 1 + } + if (item !== movedItem && item.align === to && item.index >= newIndex) { + item.index += 1 + } + }) + } + + // 更新拖拽项的位置 + if (movedItem) { + movedItem.align = to + movedItem.index = newIndex + } + } + + //判断是否在同一侧 + const isSameSide = (from, to) => { + const leftSide = [PLUGIN_POSITION.leftTop, PLUGIN_POSITION.leftBottom] + const rightSide = [PLUGIN_POSITION.rightTop, PLUGIN_POSITION.rightBottom] + + const isLeft = leftSide.includes(from) && leftSide.includes(to) + const isRight = rightSide.includes(from) && rightSide.includes(to) + + return isLeft || isRight + } + return { PLUGIN_NAME, PLUGIN_POSITION, @@ -222,6 +282,8 @@ export default () => { changeRightFixedPanels, getPluginsByLayout, changePluginLayout, - getPluginByLayout + getPluginByLayout, + dragPluginLayout, + isSameSide } } diff --git a/packages/design-core/package.json b/packages/design-core/package.json index 0c6a1234db..52a4ab324e 100644 --- a/packages/design-core/package.json +++ b/packages/design-core/package.json @@ -94,6 +94,7 @@ "prettier": "2.7.1", "sortablejs": "^1.14.0", "vue": "3.4.23", + "vue-draggable-next": "2.1.0", "vue-i18n": "^9.9.0" }, "devDependencies": { diff --git a/packages/design-core/src/App.vue b/packages/design-core/src/App.vue index 7926440cc5..1e29ecaffa 100644 --- a/packages/design-core/src/App.vue +++ b/packages/design-core/src/App.vue @@ -75,10 +75,32 @@ export default { jsClose: null }) + // Step 1: 收集插件的 align 信息 + const alignGroups = {} + const pluginList = addons.plugins + + pluginList.forEach((item) => { + if (item.id) { + const align = item.options?.align || 'leftTop' + if (!alignGroups[align]) { + alignGroups[align] = [] + } + alignGroups[align].push(item.id) + } + }) + + // Step 2: 为每个插件分配 index 值 const plugin = {} - addons.plugins.forEach((item) => { + pluginList.forEach((item) => { if (item.id) { - plugin[item.id] = { width: item.options?.width || 300, align: item.options?.align || 'rightTop' } + const align = item.options?.align || 'leftTop' + const index = alignGroups[align].indexOf(item.id) + + plugin[item.id] = { + width: item.options?.width || 300, + align: align, + index: index + } } }) localStorage.setItem('plugin', JSON.stringify(plugin)) diff --git a/packages/design-core/src/DesignPlugins.vue b/packages/design-core/src/DesignPlugins.vue index c458eaa8e4..6787b6bcdd 100644 --- a/packages/design-core/src/DesignPlugins.vue +++ b/packages/design-core/src/DesignPlugins.vue @@ -3,8 +3,15 @@
- +
+ - +
+ @@ -111,11 +139,14 @@ import { Popover, Tooltip } from '@opentiny/vue' import { useLayout, usePage } from '@opentiny/tiny-engine-controller' import { PublicIcon } from '@opentiny/tiny-engine-common' import { getPlugin } from '../config/plugin.js' +import { VueDraggableNext } from 'vue-draggable-next' + export default { components: { TinyPopover: Popover, TinyTooltip: Tooltip, - PublicIcon + PublicIcon, + VueDraggableNext }, props: { renderPanel: { @@ -138,7 +169,9 @@ export default { changeLeftFixedPanels, leftFixedPanelsStorage, getPluginsByLayout, - PLUGIN_POSITION + PLUGIN_POSITION, + dragPluginLayout, + isSameSide } = useLayout() const plugins = getPluginsByLayout().map((pluginName) => getPlugin(pluginName)) @@ -158,7 +191,8 @@ export default { prevIdex: -2, topNavLists: getPluginsByLayout(PLUGIN_POSITION.leftTop).map((pluginName) => getPlugin(pluginName)), bottomNavLists: getPluginsByLayout(PLUGIN_POSITION.leftBottom).map((pluginName) => getPlugin(pluginName)), - independence: getPluginsByLayout(PLUGIN_POSITION.independence).map((pluginName) => getPlugin(pluginName)) + independence: getPluginsByLayout(PLUGIN_POSITION.independence).map((pluginName) => getPlugin(pluginName)), + fixedNavLists: getPluginsByLayout(PLUGIN_POSITION.fixed).map((pluginName) => getPlugin(pluginName)) }) const doCompleted = () => { @@ -190,6 +224,7 @@ export default { }) } } + watch(isTemporaryPage, () => { if (isTemporaryPage.saved) { const pagePanel = state.topNavLists?.find((item) => item.id === 'AppManage') || null @@ -204,6 +239,7 @@ export default { robotComponent.value = components.Robot robotVisible.value = !robotVisible.value } + const close = () => { state.prevIdex = -2 useLayout().closePlugin(true) @@ -214,6 +250,12 @@ export default { changeLeftFixedPanels(pluginName) } + //监听拖拽结束事件 + const onEnd = (e) => { + if (!isSameSide(e.from.id, e.to.id)) close() + dragPluginLayout(e.from.id, e.to.id, e.oldIndex, e.newIndex) + } + return { state, clickMenu, @@ -228,7 +270,8 @@ export default { completed, doCompleted, pluginState, - leftFixedPanelsStorage + leftFixedPanelsStorage, + onEnd } } } diff --git a/packages/design-core/src/DesignSettings.vue b/packages/design-core/src/DesignSettings.vue index ee6738de53..00d65e1389 100644 --- a/packages/design-core/src/DesignSettings.vue +++ b/packages/design-core/src/DesignSettings.vue @@ -18,29 +18,22 @@ - +
- - + + + + +
+ @@ -50,13 +43,15 @@ import { Popover, Tooltip } from '@opentiny/vue' import { Tabs, TabItem } from '@opentiny/vue' import { useLayout } from '@opentiny/tiny-engine-controller' import { getPlugin } from '../config/plugin.js' +import { VueDraggableNext } from 'vue-draggable-next' export default { components: { TinyTabs: Tabs, TinyTabItem: TabItem, TinyPopover: Popover, - TinyTooltip: Tooltip + TinyTooltip: Tooltip, + VueDraggableNext }, props: { renderPanel: { @@ -74,6 +69,8 @@ export default { registerPluginApi, changeRightFixedPanels, getPluginsByLayout, + dragPluginLayout, + isSameSide, layoutState: { settings: settingsState } } = useLayout() @@ -121,6 +118,12 @@ export default { changeRightFixedPanels(pluginName) } + //监听拖拽结束事件 + const onEnd = (e) => { + if (!isSameSide(e.from.id, e.to.id)) close() + dragPluginLayout(e.from.id, e.to.id, e.oldIndex, e.newIndex) + } + return { state, showMask, @@ -131,7 +134,8 @@ export default { clickMenu, close, fixPanel, - rightFixedPanelsStorage + rightFixedPanelsStorage, + onEnd } } } @@ -269,4 +273,9 @@ export default { box-shadow: inset 0px 0px 14px var(--ti-lowcode-canvas-handle-hover-bg); } } + +.ghost { + opacity: 0.5; + background: #f2f2f2; +} diff --git a/packages/plugins/help/index.js b/packages/plugins/help/index.js index 32727a3152..7ef4be42cd 100644 --- a/packages/plugins/help/index.js +++ b/packages/plugins/help/index.js @@ -17,7 +17,7 @@ export default { title: '', icon: HelpIcon, options: { - align: 'leftBottom' + align: 'fixed' }, align: 'bottom' }