feat: plugin flexible layout (#1219)
This commit is contained in:
parent
20c3b071bd
commit
8d31bd3ed4
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<component :is="CanvasLayout">
|
<component :is="CanvasLayout" :class="{ 'not-selected': getMoveDragBarState() }">
|
||||||
<template #header>
|
<template #header>
|
||||||
<component v-if="!isBlock()" :is="CanvasRouteBar"></component>
|
<component v-if="!isBlock()" :is="CanvasRouteBar"></component>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -67,6 +67,8 @@ export default {
|
||||||
const { canvasSrc = '' } = getOptions(meta.id) || {}
|
const { canvasSrc = '' } = getOptions(meta.id) || {}
|
||||||
const canvasSrcDoc = ref('')
|
const canvasSrcDoc = ref('')
|
||||||
|
|
||||||
|
const { getMoveDragBarState, getFixedPanelsStatus, closePlugin, closeSetting } = useLayout()
|
||||||
|
|
||||||
useMessage().subscribe({
|
useMessage().subscribe({
|
||||||
topic: 'init_canvas_deps',
|
topic: 'init_canvas_deps',
|
||||||
subscriber: 'canvas_design_canvas',
|
subscriber: 'canvas_design_canvas',
|
||||||
|
|
@ -151,9 +153,17 @@ export default {
|
||||||
)
|
)
|
||||||
|
|
||||||
const nodeSelected = (node, parent, type, id) => {
|
const nodeSelected = (node, parent, type, id) => {
|
||||||
|
const { leftPanelFixed, rightPanelFixed } = getFixedPanelsStatus()
|
||||||
|
|
||||||
const { toolbars } = useLayout().layoutState
|
const { toolbars } = useLayout().layoutState
|
||||||
if (type !== 'clickTree') {
|
if (type !== 'clickTree') {
|
||||||
useLayout().closePlugin()
|
if (!leftPanelFixed) {
|
||||||
|
closePlugin()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rightPanelFixed) {
|
||||||
|
closeSetting(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { getSchema, getNodePath } = useCanvas()
|
const { getSchema, getNodePath } = useCanvas()
|
||||||
|
|
@ -275,6 +285,7 @@ export default {
|
||||||
useNotify
|
useNotify
|
||||||
},
|
},
|
||||||
isBlock,
|
isBlock,
|
||||||
|
getMoveDragBarState,
|
||||||
CanvasLayout,
|
CanvasLayout,
|
||||||
canvasRef,
|
canvasRef,
|
||||||
CanvasContainer,
|
CanvasContainer,
|
||||||
|
|
@ -284,3 +295,10 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.not-selected {
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ export default {
|
||||||
|
|
||||||
watch(() => useLayout().getDimension().width, setScale, { flush: 'post', immediate: true })
|
watch(() => useLayout().getDimension().width, setScale, { flush: 'post', immediate: true })
|
||||||
|
|
||||||
watch(() => useLayout().getPluginState().fixedPanels, setScale, { flush: 'post' })
|
watch(() => useLayout().leftFixedPanelsStorage.value, setScale, { flush: 'post' })
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => useLayout().getPluginState().render,
|
() => useLayout().getPluginState().render,
|
||||||
|
|
@ -106,6 +106,20 @@ export default {
|
||||||
{ flush: 'post' }
|
{ flush: 'post' }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
watch(() => useLayout().rightFixedPanelsStorage.value, setScale, { flush: 'post' })
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => useLayout().getSettingState().render,
|
||||||
|
(value) => {
|
||||||
|
const currentFixed = useLayout().rightFixedPanelsStorage.value.includes(value)
|
||||||
|
|
||||||
|
if (!value || currentFixed) {
|
||||||
|
setScale()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ flush: 'post' }
|
||||||
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => sizeStyle.value,
|
() => sizeStyle.value,
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="plugin-panel">
|
<div class="plugin-panel" ref="panel" :style="{ width: panelWidth + 'px' }">
|
||||||
<div class="plugin-panel-header">
|
<div :class="['plugin-panel-header', headerBottomLine]">
|
||||||
<div class="plugin-panel-title">
|
<div class="plugin-panel-title">
|
||||||
<span class="title"
|
<span class="title"
|
||||||
>{{ title }}<link-button class="link" v-if="isShowDocsIcon" :href="docsUrl"></link-button
|
>{{ title }}<link-button class="link" v-if="isShowDocsIcon" :href="docsUrl"></link-button
|
||||||
|
|
@ -9,22 +9,53 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="plugin-panel-icon">
|
<div class="plugin-panel-icon">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
|
<tiny-tooltip
|
||||||
|
v-if="isShowCollapseIcon"
|
||||||
|
effect="light"
|
||||||
|
:content="isCollapsed ? '展开' : '折叠'"
|
||||||
|
placement="top"
|
||||||
|
:visible-arrow="false"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<svg-button :name="settingIcon" @click="clickCollapseIcon"></svg-button>
|
||||||
|
</template>
|
||||||
|
</tiny-tooltip>
|
||||||
|
<svg-button
|
||||||
|
class="item icon-sidebar"
|
||||||
|
:name="fixedPanels?.includes(fixedName) ? 'fixed-solid' : 'fixed'"
|
||||||
|
:tips="!fixedPanels?.includes(fixedName) ? '固定面板' : '解除固定面板'"
|
||||||
|
@click="fixPanel"
|
||||||
|
></svg-button>
|
||||||
<close-icon v-if="!isCloseLeft" :name="name" @close="closePanel"></close-icon>
|
<close-icon v-if="!isCloseLeft" :name="name" @close="closePanel"></close-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<slot name="content"></slot>
|
<div class="scroll-content">
|
||||||
|
<slot name="content"></slot>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="isWidthResizable">
|
||||||
|
<div class="resizer-right" v-if="isLeftResizer" @mousedown="onMouseDownRight"></div>
|
||||||
|
<div class="resizer-left" v-if="isRightResizer" @mousedown="onMouseDownLeft"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useThrottleFn } from '@vueuse/core'
|
||||||
|
import { inject, ref, computed, onMounted, provide } from 'vue'
|
||||||
import { useLayout } from '@opentiny/tiny-engine-meta-register'
|
import { useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
|
import { SvgButton } from '@opentiny/tiny-engine-common'
|
||||||
|
import { constants } from '@opentiny/tiny-engine-utils'
|
||||||
import LinkButton from './LinkButton.vue'
|
import LinkButton from './LinkButton.vue'
|
||||||
import CloseIcon from './CloseIcon.vue'
|
import CloseIcon from './CloseIcon.vue'
|
||||||
|
import { Tooltip } from '@opentiny/vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
TinyTooltip: Tooltip,
|
||||||
LinkButton,
|
LinkButton,
|
||||||
CloseIcon
|
CloseIcon,
|
||||||
|
SvgButton
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
/**
|
/**
|
||||||
|
|
@ -52,18 +83,151 @@ export default {
|
||||||
isShowDocsIcon: {
|
isShowDocsIcon: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 固定面板插件数组
|
||||||
|
*/
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 固定面板标识
|
||||||
|
*/
|
||||||
|
fixedName: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 是否展示标题下边线
|
||||||
|
*/
|
||||||
|
showBottomBorder: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 是否展示折叠按钮
|
||||||
|
*/
|
||||||
|
isShowCollapseIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['close'],
|
emits: ['close', 'updateCollapseStatus'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const closePanel = () => {
|
const closePanel = () => {
|
||||||
useLayout().closePlugin()
|
|
||||||
|
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { PLUGIN_DEFAULT_WIDTH } = constants
|
||||||
|
|
||||||
|
const MIN_WIDTH = PLUGIN_DEFAULT_WIDTH // 固定的最小宽度值
|
||||||
|
const MAX_WIDTH = 1000 // 固定的最大宽度值
|
||||||
|
const panel = ref(null)
|
||||||
|
let startX = 0
|
||||||
|
let startWidth = 0
|
||||||
|
|
||||||
|
const isCollapsed = ref(false)
|
||||||
|
const settingIcon = computed(() => (isCollapsed.value ? 'collapse_all' : 'expand_all'))
|
||||||
|
|
||||||
|
provide('isCollapsed', isCollapsed)
|
||||||
|
|
||||||
|
const panelState = inject('panelState')
|
||||||
|
const fixPanel = () => {
|
||||||
|
panelState.emitEvent('fixPanel', props.fixedName)
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerBottomLine = computed(() => (props.showBottomBorder ? 'header-bottom-line' : ''))
|
||||||
|
|
||||||
|
const { getPluginWidth, changePluginWidth, getPluginByLayout, changeMoveDragBarState, isPanelWidthResizable } =
|
||||||
|
useLayout()
|
||||||
|
|
||||||
|
const align = ref(getPluginByLayout(props.fixedName)) // 滚动条位置
|
||||||
|
const panelWidth = ref(getPluginWidth(props.fixedName)) // 面板使用默认宽度
|
||||||
|
const isLeftResizer = ref(align.value.includes('left'))
|
||||||
|
const isRightResizer = ref(align.value.includes('right'))
|
||||||
|
const isWidthResizable = computed(() => isPanelWidthResizable(props.fixedName))
|
||||||
|
|
||||||
|
const onMouseMoveRight = (event) => {
|
||||||
|
const newWidth = startWidth + (event.clientX - startX)
|
||||||
|
panelWidth.value = Math.max(MIN_WIDTH, Math.min(newWidth, MAX_WIDTH))
|
||||||
|
changePluginWidth(props.fixedName, panelWidth.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseMoveLeft = (event) => {
|
||||||
|
const newWidth = startWidth - (event.clientX - startX)
|
||||||
|
panelWidth.value = Math.max(MIN_WIDTH, Math.min(newWidth, MAX_WIDTH))
|
||||||
|
changePluginWidth(props.fixedName, panelWidth.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const throttledMouseMoveRight = useThrottleFn(onMouseMoveRight, 50)
|
||||||
|
const throttledMouseMoveLeft = useThrottleFn(onMouseMoveLeft, 50)
|
||||||
|
|
||||||
|
const leftResizer = ref(null)
|
||||||
|
const rightResizer = ref(null)
|
||||||
|
|
||||||
|
const onMouseUpRight = () => {
|
||||||
|
changeMoveDragBarState(false)
|
||||||
|
document.removeEventListener('mousemove', throttledMouseMoveRight)
|
||||||
|
document.removeEventListener('mouseup', onMouseUpRight)
|
||||||
|
rightResizer.value.style.cursor = ''
|
||||||
|
rightResizer.value.classList.remove('dragging')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseDownRight = (event) => {
|
||||||
|
changeMoveDragBarState(true)
|
||||||
|
startX = event.clientX
|
||||||
|
startWidth = panel.value.offsetWidth
|
||||||
|
document.addEventListener('mousemove', throttledMouseMoveRight)
|
||||||
|
document.addEventListener('mouseup', onMouseUpRight)
|
||||||
|
rightResizer.value.style.cursor = 'ew-resize'
|
||||||
|
rightResizer.value.classList.add('dragging')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseUpLeft = () => {
|
||||||
|
changeMoveDragBarState(false)
|
||||||
|
document.removeEventListener('mousemove', throttledMouseMoveLeft)
|
||||||
|
document.removeEventListener('mouseup', onMouseUpLeft)
|
||||||
|
leftResizer.value.style.cursor = ''
|
||||||
|
leftResizer.value.classList.remove('dragging')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseDownLeft = (event) => {
|
||||||
|
changeMoveDragBarState(true)
|
||||||
|
startX = event.clientX
|
||||||
|
startWidth = panel.value.offsetWidth
|
||||||
|
document.addEventListener('mousemove', throttledMouseMoveLeft)
|
||||||
|
document.addEventListener('mouseup', onMouseUpLeft)
|
||||||
|
leftResizer.value.style.cursor = 'ew-resize'
|
||||||
|
leftResizer.value.classList.add('dragging')
|
||||||
|
}
|
||||||
|
|
||||||
|
const initResizerDOM = () => {
|
||||||
|
leftResizer.value = document.querySelector('.resizer-left')
|
||||||
|
rightResizer.value = document.querySelector('.resizer-right')
|
||||||
|
}
|
||||||
|
|
||||||
|
const clickCollapseIcon = () => {
|
||||||
|
isCollapsed.value = !isCollapsed.value
|
||||||
|
emit('updateCollapseStatus', isCollapsed.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initResizerDOM()
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
closePanel
|
isWidthResizable,
|
||||||
|
headerBottomLine,
|
||||||
|
clickCollapseIcon,
|
||||||
|
isCollapsed,
|
||||||
|
settingIcon,
|
||||||
|
closePanel,
|
||||||
|
fixPanel,
|
||||||
|
panel,
|
||||||
|
panelWidth,
|
||||||
|
onMouseDownRight,
|
||||||
|
onMouseDownLeft,
|
||||||
|
isLeftResizer,
|
||||||
|
isRightResizer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -88,12 +252,15 @@ export default {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
color: var(--te-component-common-text-color-primary);
|
color: var(--te-component-common-text-color-primary);
|
||||||
font-weight: var(--te-base-font-weight-7);
|
font-weight: var(--te-base-font-weight-7);
|
||||||
|
|
||||||
.plugin-panel-title {
|
.plugin-panel-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.title + .icon-wrap {
|
.title + .icon-wrap {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -109,10 +276,65 @@ export default {
|
||||||
:deep(.svg-button + .svg-button) {
|
:deep(.svg-button + .svg-button) {
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.svg-button + .icon-wrap) {
|
:deep(.svg-button + .icon-wrap) {
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右边拖拽线
|
||||||
|
.resizer-right {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 1px;
|
||||||
|
height: 100%;
|
||||||
|
cursor: ew-resize;
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-bottom-line {
|
||||||
|
border-bottom: 1px solid var(--te-common-border-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dragging {
|
||||||
|
width: 2px !important;
|
||||||
|
background-color: var(--te-component-common-resizer-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resizer-right:hover {
|
||||||
|
width: 2px;
|
||||||
|
background-color: var(--te-component-common-resizer-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 左边拖拽线
|
||||||
|
.resizer-left {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 1px;
|
||||||
|
height: 100%;
|
||||||
|
cursor: ew-resize;
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resizer-left:hover {
|
||||||
|
width: 2px;
|
||||||
|
background-color: var(--te-component-common-resizer-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-content {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-content::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
<template>
|
||||||
|
<ul v-if="false" class="plugin-context-menu" :style="{ left: contextMenu.x + 'px', top: contextMenu.y + 'px' }">
|
||||||
|
<li v-if="contextMenu.type" @click="hidePlugin">隐藏 "{{ contextMenu.item.title }}"</li>
|
||||||
|
<li v-if="contextMenu.type" class="bottom-li" @click="switchAlign">
|
||||||
|
切换到{{ align.includes('right') ? '左侧' : '右侧' }}
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in list"
|
||||||
|
:key="index"
|
||||||
|
@click.stop="changeShowState(item.id)"
|
||||||
|
class="menu-item-wrapper"
|
||||||
|
:class="{
|
||||||
|
'bottom-li': index === list.length - 1
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span class="check-mark">
|
||||||
|
<span v-show="getPluginShown(item.id)">√</span>
|
||||||
|
</span>
|
||||||
|
<span>{{ item.title }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, onMounted, onBeforeUnmount, nextTick, ref } from 'vue'
|
||||||
|
import { useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
list: {
|
||||||
|
type: Array
|
||||||
|
},
|
||||||
|
align: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['close', 'switchAlign'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const { getPluginShown, changePluginShown, changeMenuShown } = useLayout()
|
||||||
|
const pluginGroupPosition = ref('')
|
||||||
|
const contextMenu = reactive({
|
||||||
|
type: true,
|
||||||
|
visible: false,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
item: null,
|
||||||
|
index: null,
|
||||||
|
list: null
|
||||||
|
})
|
||||||
|
|
||||||
|
// 显示菜单
|
||||||
|
const contextMenuWidth = props.align.includes('right') ? 130 : 0
|
||||||
|
const showContextMenu = (x, y, type, item, index, position) => {
|
||||||
|
const windowHeight = window.innerHeight
|
||||||
|
|
||||||
|
contextMenu.type = type
|
||||||
|
contextMenu.visible = true
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
const pluginMenuPanel = document.querySelector('.plugin-context-menu')
|
||||||
|
const menuHeight = pluginMenuPanel?.offsetHeight
|
||||||
|
|
||||||
|
const spaceBelow = windowHeight - y - 20
|
||||||
|
|
||||||
|
if (menuHeight && spaceBelow < menuHeight) {
|
||||||
|
contextMenu.y = y - menuHeight
|
||||||
|
} else {
|
||||||
|
contextMenu.y = y
|
||||||
|
}
|
||||||
|
|
||||||
|
contextMenu.x = x - contextMenuWidth
|
||||||
|
})
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
contextMenu.item = item
|
||||||
|
contextMenu.index = index
|
||||||
|
pluginGroupPosition.value = position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏菜单
|
||||||
|
const hideContextMenu = () => {
|
||||||
|
contextMenu.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏插件
|
||||||
|
const hidePlugin = () => {
|
||||||
|
emit('close')
|
||||||
|
changePluginShown(contextMenu.item.id)
|
||||||
|
hideContextMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换组件位置
|
||||||
|
const switchAlign = () => {
|
||||||
|
emit('close')
|
||||||
|
emit('switchAlign', contextMenu.index, contextMenu.item.id, pluginGroupPosition.value)
|
||||||
|
hideContextMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏活动栏
|
||||||
|
const hideSidebar = () => {
|
||||||
|
const align = props.align.includes('right') ? 'right' : 'left'
|
||||||
|
changeMenuShown(align)
|
||||||
|
hideContextMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 改变组件显示状态
|
||||||
|
const changeShowState = (pluginName) => {
|
||||||
|
changePluginShown(pluginName)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClickOutside = (event) => {
|
||||||
|
if (!event.target.closest('.plugin-context-menu')) {
|
||||||
|
hideContextMenu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('click', handleClickOutside)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
document.removeEventListener('click', handleClickOutside)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
contextMenu,
|
||||||
|
showContextMenu,
|
||||||
|
changeShowState,
|
||||||
|
getPluginShown,
|
||||||
|
hidePlugin,
|
||||||
|
switchAlign,
|
||||||
|
hideSidebar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 引入B的CSS样式 */
|
||||||
|
.plugin-context-menu {
|
||||||
|
position: absolute;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
list-style: none;
|
||||||
|
width: 135px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-context-menu-header {
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: default;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.bottom-li {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-context-menu li {
|
||||||
|
padding: 8px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-context-menu li:hover {
|
||||||
|
background: #f0f0f0;
|
||||||
|
}
|
||||||
|
.menu-item-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-mark {
|
||||||
|
width: 20px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,6 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="['plugin-setting', { 'second-panel': isSecond }, { 'full-screen': state.isFullScreen }]"
|
id="panel-setting"
|
||||||
|
:class="[
|
||||||
|
'plugin-setting',
|
||||||
|
{ 'second-panel': isSecond },
|
||||||
|
{ 'full-screen': state.isFullScreen },
|
||||||
|
{ 'align-right': align.includes('right') },
|
||||||
|
shadowClass
|
||||||
|
]"
|
||||||
|
:style="alignStyle"
|
||||||
@click="$emit('click')"
|
@click="$emit('click')"
|
||||||
>
|
>
|
||||||
<div class="plugin-setting-header">
|
<div class="plugin-setting-header">
|
||||||
|
|
@ -31,11 +39,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reactive, watchEffect } from 'vue'
|
import { nextTick, reactive, watchEffect, computed } from 'vue'
|
||||||
import { Button } from '@opentiny/vue'
|
import { Button } from '@opentiny/vue'
|
||||||
import { iconPlus } from '@opentiny/vue-icon'
|
import { iconPlus } from '@opentiny/vue-icon'
|
||||||
import ButtonGroup from './ButtonGroup.vue'
|
import ButtonGroup from './ButtonGroup.vue'
|
||||||
import SvgButton from './SvgButton.vue'
|
import SvgButton from './SvgButton.vue'
|
||||||
|
import { useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
|
|
||||||
const EVENTS = {
|
const EVENTS = {
|
||||||
FULL_SCREEN_CHANGE: 'fullScreenChange',
|
FULL_SCREEN_CHANGE: 'fullScreenChange',
|
||||||
|
|
@ -91,6 +100,14 @@ export default {
|
||||||
icon: {
|
icon: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: iconPlus()
|
default: iconPlus()
|
||||||
|
},
|
||||||
|
fixedName: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
align: {
|
||||||
|
type: String,
|
||||||
|
default: 'leftTop'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: [EVENTS.FULL_SCREEN_CHANGE, EVENTS.SAVE, EVENTS.CANCEL, EVENTS.ADD, EVENTS.CLICK],
|
emits: [EVENTS.FULL_SCREEN_CHANGE, EVENTS.SAVE, EVENTS.CANCEL, EVENTS.ADD, EVENTS.CLICK],
|
||||||
|
|
@ -99,6 +116,28 @@ export default {
|
||||||
isFullScreen: false
|
isFullScreen: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { getPluginWidth } = useLayout()
|
||||||
|
|
||||||
|
const firstPanelOffset = computed(() => {
|
||||||
|
return getPluginWidth(props.fixedName) + 1
|
||||||
|
})
|
||||||
|
|
||||||
|
const secondPanelAlign = computed(() => {
|
||||||
|
return props.align.includes('left') ? 'left' : 'right'
|
||||||
|
})
|
||||||
|
|
||||||
|
const alignStyle = computed(() => {
|
||||||
|
return `${secondPanelAlign.value} : ${firstPanelOffset.value}px`
|
||||||
|
})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
// 处理二级面板偏移量
|
||||||
|
const secondPanelOffset = document.querySelector('.plugin-setting')?.clientWidth + firstPanelOffset.value
|
||||||
|
nextTick(() => {
|
||||||
|
document.querySelector('.second-panel')?.style.setProperty(secondPanelAlign.value, `${secondPanelOffset}px`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
state.isFullScreen = props.isFullScreen
|
state.isFullScreen = props.isFullScreen
|
||||||
})
|
})
|
||||||
|
|
@ -112,7 +151,16 @@ export default {
|
||||||
return isFullScreen ? '收起' : '全屏查看'
|
return isFullScreen ? '收起' : '全屏查看'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 计算属性用于确定阴影类
|
||||||
|
const shadowClass = computed(() => {
|
||||||
|
if (props.isSecond) return ''
|
||||||
|
return props.align.includes('right') ? 'shadow-right' : 'shadow-left'
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
alignStyle,
|
||||||
|
shadowClass,
|
||||||
|
firstPanelOffset,
|
||||||
state,
|
state,
|
||||||
fullScreen,
|
fullScreen,
|
||||||
getFullScreenLabel
|
getFullScreenLabel
|
||||||
|
|
@ -124,7 +172,6 @@ export default {
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.plugin-setting {
|
.plugin-setting {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: var(--base-left-panel-width);
|
|
||||||
top: 0;
|
top: 0;
|
||||||
width: var(--base-collection-panel-width);
|
width: var(--base-collection-panel-width);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -132,17 +179,24 @@ export default {
|
||||||
background: var(--te-component-common-bg-color);
|
background: var(--te-component-common-bg-color);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-left: 1px solid var(--te-component-common-border-color-divider);
|
border-left: 1px solid var(--te-component-common-border-color-divider);
|
||||||
|
|
||||||
&:not(.second-panel) {
|
&:not(.second-panel) {
|
||||||
box-shadow: 6px 0px 3px 0px var(--te-component-common-shadow-color);
|
&.shadow-left {
|
||||||
border-right: none;
|
box-shadow: 6px 0px 3px 0px var(--te-component-common-shadow-color);
|
||||||
border-left: none;
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.shadow-right {
|
||||||
|
box-shadow: -6px 0px 3px 0px var(--te-component-common-shadow-color);
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.full-screen {
|
&.full-screen {
|
||||||
width: var(--base-collection-panel-full-screen-width);
|
width: var(--base-collection-panel-full-screen-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.second-panel {
|
&.second-panel {
|
||||||
left: calc(var(--base-left-panel-width) + var(--base-collection-panel-width));
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,6 +221,7 @@ export default {
|
||||||
color: var(--te-component-common-text-color-primary);
|
color: var(--te-component-common-text-color-primary);
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
border-bottom: 1px solid var(--te-component-common-border-color-divider);
|
border-bottom: 1px solid var(--te-component-common-border-color-divider);
|
||||||
|
|
||||||
.plugin-setting-header-title {
|
.plugin-setting-header-title {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|
@ -175,9 +230,11 @@ export default {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.svg-button + .svg-button) {
|
:deep(.svg-button + .svg-button) {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.tiny-button.tiny-button) {
|
:deep(.tiny-button.tiny-button) {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -195,4 +252,8 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.align-right {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import ConfigGroup from './ConfigGroup.vue'
|
||||||
import ConfigItem from './ConfigItem.vue'
|
import ConfigItem from './ConfigItem.vue'
|
||||||
export { default as PluginSetting } from './PluginSetting.vue'
|
export { default as PluginSetting } from './PluginSetting.vue'
|
||||||
export { default as PluginPanel } from './PluginPanel.vue'
|
export { default as PluginPanel } from './PluginPanel.vue'
|
||||||
|
export { default as PluginRightMenu } from './PluginRightMenu.vue'
|
||||||
export { default as SvgButton } from './SvgButton.vue'
|
export { default as SvgButton } from './SvgButton.vue'
|
||||||
export { default as LinkButton } from './LinkButton.vue'
|
export { default as LinkButton } from './LinkButton.vue'
|
||||||
export { default as ConfigCollapse } from './ConfigCollapse.vue'
|
export { default as ConfigCollapse } from './ConfigCollapse.vue'
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,14 @@
|
||||||
"eslint-linter-browserify": "8.57.0",
|
"eslint-linter-browserify": "8.57.0",
|
||||||
"monaco-editor": "0.51.0",
|
"monaco-editor": "0.51.0",
|
||||||
"prettier": "2.7.1",
|
"prettier": "2.7.1",
|
||||||
"vue-draggable-next": "2.1.0"
|
"vue-draggable-next": "2.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opentiny/tiny-engine-vite-plugin-meta-comments": "workspace:*",
|
"@opentiny/tiny-engine-vite-plugin-meta-comments": "workspace:*",
|
||||||
"@vitejs/plugin-vue": "^5.1.2",
|
"@vitejs/plugin-vue": "^5.1.2",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
||||||
"glob": "^10.3.4",
|
"glob": "^10.3.4",
|
||||||
|
"@vueuse/core": "^9.6.0",
|
||||||
"vite": "^5.4.2"
|
"vite": "^5.4.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
--te-component-common-border-color-transparent: var(--te-base-color-transparent); // 透明色直接使用base的变量
|
--te-component-common-border-color-transparent: var(--te-base-color-transparent); // 透明色直接使用base的变量
|
||||||
--te-component-common-button-border-color: var(--te-common-border-secondary);
|
--te-component-common-button-border-color: var(--te-common-border-secondary);
|
||||||
|
|
||||||
|
--te-component-common-resizer-border-color: var(--te-base-blue-70);
|
||||||
|
|
||||||
--te-component-common-shadow-color: var(--te-common-shadow-panel);
|
--te-component-common-shadow-color: var(--te-common-shadow-panel);
|
||||||
|
|
||||||
--te-component-config-item-bind-bg-color: var(--te-common-bg-info);
|
--te-component-config-item-bind-bg-color: var(--te-common-bg-info);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
"@opentiny/tiny-engine-utils": "workspace:*",
|
"@opentiny/tiny-engine-utils": "workspace:*",
|
||||||
"@vue/shared": "^3.3.4",
|
"@vue/shared": "^3.3.4",
|
||||||
"monaco-editor": "0.51.0",
|
"monaco-editor": "0.51.0",
|
||||||
"vue-draggable-next": "2.1.0"
|
"vue-draggable-next": "2.2.1"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,26 @@
|
||||||
<svg
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
data-icon="DisplayInline"
|
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
aria-hidden="true"
|
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
focusable="false"
|
viewBox="0 0 132 132" style="enable-background:new 0 0 132 132;" xml:space="preserve">
|
||||||
width="16"
|
<style type="text/css">
|
||||||
height="16"
|
.st0{fill:none;}
|
||||||
viewBox="0 0 16 16"
|
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:currentColor;}
|
||||||
version="1.1"
|
</style>
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<rect id="size" class="st0" width="132" height="132"/>
|
||||||
style="display: block"
|
<path id="矢量_28" class="st1" d="M8.2,66C8.2,34.1,34.1,8.2,66,8.2c31.9,0,57.8,25.8,57.8,57.8c0,15.9-35.8,0.9-39.9,19.2
|
||||||
>
|
c-0.7,3,1.1,8.8,3,14.8c2.7,8.6,5.4,17.6,1.3,19.3c-6.8,2.8-14.3,4.4-22.1,4.4C34.1,123.8,8.2,97.9,8.2,66z M46.7,20.4
|
||||||
<path opacity=".6" fill-rule="evenodd" clip-rule="evenodd" d="M1 2h1v12H1V2zm14 0h-1v12h1V2z"></path>
|
c2.7-1.1,5.4-2,8.2-2.6c3.6-0.8,7.3-1.2,11.1-1.2c3.8,0,7.5,0.4,11.1,1.2c2.8,0.6,5.5,1.5,8.2,2.6c2.8,1.2,5.3,2.6,7.8,4.2
|
||||||
<path
|
c2.8,1.8,5.5,4,7.9,6.4s4.6,5.1,6.5,7.9v0c1.6,2.5,3,5.1,4.2,7.8c1.1,2.7,2,5.4,2.7,8.2l0,0c0.8,3.4,1.2,6.8,1.2,10.4
|
||||||
fill-rule="evenodd"
|
c-0.8,0.3-2,0.5-3.6,0.7c-1.2,0.1-3.2,0.3-6.1,0.4c-3.4,0.2-6,0.4-7.8,0.6c-3.2,0.4-6.1,1-8.5,1.8c-3.4,1.1-6.2,2.8-8.4,5
|
||||||
clip-rule="evenodd"
|
c-0.9,0.9-1.7,1.9-2.4,2.9c-1.4,2-2.3,4.3-2.9,6.8c-0.3,1.6-0.4,3.3-0.2,5.3c0.1,1.3,0.4,2.9,0.8,4.6c0.4,1.9,1.3,5,2.6,9.1
|
||||||
d="M7.25 3L3.5 13h2l1-3h3l1 3h2L8.75 3h-1.5zm1.917 6L8 5.5 6.833 9h2.334z"
|
c0.9,2.8,1.5,4.8,1.8,6.1c0.5,1.7,0.8,3.1,1,4.3c-1.6,0.5-3.2,1-4.8,1.4c-3.5,0.8-7.2,1.2-10.9,1.2c-3.8,0-7.5-0.4-11.1-1.2
|
||||||
></path>
|
c-2.8-0.6-5.5-1.5-8.2-2.7c-2.8-1.2-5.3-2.6-7.8-4.2c-2.8-1.9-5.5-4-7.9-6.5s-4.6-5.1-6.5-7.9c-1.6-2.5-3-5.1-4.2-7.8
|
||||||
|
c-1.1-2.7-2-5.4-2.6-8.2c-0.8-3.6-1.2-7.3-1.2-11.1c0-3.8,0.4-7.5,1.2-11.1c0.6-2.8,1.5-5.5,2.6-8.2c1.2-2.8,2.6-5.3,4.2-7.8
|
||||||
|
c1.8-2.8,4-5.5,6.4-7.9s5.1-4.6,7.9-6.4l0,0l0,0l0,0C41.4,22.9,44,21.5,46.7,20.4z M33,45.4C33,38.5,38.5,33,45.4,33
|
||||||
|
s12.4,5.5,12.4,12.4s-5.5,12.4-12.4,12.4S33,52.2,33,45.4z M86.6,33c-6.8,0-12.4,5.5-12.4,12.4s5.5,12.4,12.4,12.4
|
||||||
|
c6.8,0,12.4-5.5,12.4-12.4S93.4,33,86.6,33z M41.2,45.4c0-2.3,1.8-4.1,4.1-4.1c2.3,0,4.1,1.8,4.1,4.1c0,2.3-1.8,4.1-4.1,4.1
|
||||||
|
C43.1,49.5,41.2,47.7,41.2,45.4z M86.6,41.2c-2.3,0-4.1,1.8-4.1,4.1c0,2.3,1.8,4.1,4.1,4.1c2.3,0,4.1-1.8,4.1-4.1
|
||||||
|
C90.8,43.1,88.9,41.2,86.6,41.2z M45.4,74.2c-6.8,0-12.4,5.5-12.4,12.4C33,93.4,38.5,99,45.4,99s12.4-5.6,12.4-12.4
|
||||||
|
C57.8,79.8,52.2,74.2,45.4,74.2z M45.4,82.5c-2.3,0-4.1,1.8-4.1,4.1c0,2.3,1.8,4.1,4.1,4.1c2.3,0,4.1-1.8,4.1-4.1
|
||||||
|
C49.5,84.3,47.7,82.5,45.4,82.5z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 2.3 KiB |
|
|
@ -1,17 +1,17 @@
|
||||||
<svg version="1.1" id="图层_1"
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
<style type="text/css">
|
viewBox="0 0 132 132" style="enable-background:new 0 0 132 132;" xml:space="preserve">
|
||||||
.st0{fill:currentcolor;}
|
<style type="text/css">
|
||||||
</style>
|
.st0{fill:none;}
|
||||||
<g>
|
.st1{fill:currentColor;}
|
||||||
<path class="st0" d="M57.5,9.2h-51c-1.1,0-2,0.9-2,2v39.7c0,1.1,0.9,2,2,2h51.1c1.1,0,2-0.9,2-2V11.2C59.5,10.1,58.7,9.2,57.5,9.2z
|
</style>
|
||||||
M55.5,48.9h-47V13.2h47.1L55.5,48.9L55.5,48.9z"/>
|
<rect id="size" class="st0" width="132" height="132"/>
|
||||||
<rect x="14.3" y="20.6" class="st0" width="5.3" height="3"/>
|
<path id="形状结合" class="st1" d="M119.6,33h-12.9c-2.1-9.6-10.3-16.5-20.1-16.5c-9.9,0-18.2,6.9-20.2,16.5h-54
|
||||||
<rect x="25.1" y="20.6" class="st0" width="24.5" height="3"/>
|
c-2.3,0-4.1,1.8-4.1,4.1c0,2.2,1.8,4.1,4.1,4.1h54c2.1,9.5,10.3,16.5,20.2,16.5c9.8,0,18.1-7,20.1-16.5h12.9c2.2,0,4.1-1.9,4.1-4.1
|
||||||
<rect x="14.3" y="29.6" class="st0" width="5.3" height="3"/>
|
C123.8,34.8,121.8,33,119.6,33z M86.6,49.5c-7,0-12.4-5.5-12.4-12.4c0-7,5.4-12.4,12.4-12.4c6.9,0,12.4,5.4,12.4,12.4
|
||||||
<rect x="25.1" y="29.6" class="st0" width="24.5" height="3"/>
|
C99,44,93.6,49.5,86.6,49.5z M12.4,99h12.8c2.1,9.5,10.3,16.5,20.2,16.5c9.8,0,18.1-7,20.1-16.5h54.1c2.2,0,4.1-1.9,4.1-4.1
|
||||||
<rect x="14.3" y="38.5" class="st0" width="5.3" height="3"/>
|
c0-2.3-1.9-4.1-4.1-4.1H65.5c-2.1-9.6-10.3-16.5-20.1-16.5c-9.9,0-18.1,6.9-20.2,16.5H12.4c-2.3,0-4.1,1.8-4.1,4.1
|
||||||
<rect x="25.1" y="38.5" class="st0" width="24.5" height="3"/>
|
C8.2,97.1,10.1,99,12.4,99z M45.4,82.5c6.9,0,12.4,5.4,12.4,12.4c0,6.9-5.5,12.4-12.4,12.4c-7,0-12.4-5.4-12.4-12.4
|
||||||
</g>
|
C33,87.9,38.4,82.5,45.4,82.5z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 877 B After Width: | Height: | Size: 1.2 KiB |
|
|
@ -1,3 +1,25 @@
|
||||||
<svg data-icon="Target" aria-hidden="true" focusable="false" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 2H7v2H4v3H2v2h2v3h3v2h2v-2h3V9h2V7h-2V4H9V2zm1 5V6H6v4h4V7z" fill="currentColor"></path>
|
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 132 132" style="enable-background:new 0 0 132 132;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:none;}
|
||||||
|
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:currentColor;}
|
||||||
|
</style>
|
||||||
|
<rect id="size" class="st0" width="132" height="132"/>
|
||||||
|
<path id="矢量_29" class="st1" d="M79.1,13.5C76.7,9.4,72.6,7,68,7H53.3l-1.5,0.2l-1.3,0.2c-3.9,1.1-6.9,3.7-8.5,7.3l-3.5,8
|
||||||
|
l-1.7,1l-8.7-1l-1.2-0.1c-4.7,0-8.9,2.3-11.2,6.3L8.2,41.7L7.6,43l-0.4,1.2c-1,3.9-0.2,7.8,2.1,11l5.3,7v1.9l-5.3,7l-0.8,1.2
|
||||||
|
C6.2,76.4,6.2,81.1,8.4,85l7.4,12.8l0.8,1.1l0.9,1.1c2.8,2.8,6.7,4.1,10.5,3.6l8.7-1.1l1.7,1.1l3.5,8l0.6,1.1
|
||||||
|
c2.4,4.1,6.5,6.5,11,6.5h7.3v-8.2h-7.3c-1.6,0-3.4-1.5-4.1-2.9l-3.9-9.1c-0.4-0.8-1-1.5-1.7-2l-4.1-2.3c-0.8-0.5-1.6-0.7-2.6-0.6
|
||||||
|
L27,95.5c-1.5,0.2-3.4-1.1-4.3-2.2l-7.3-12.4c-0.8-1.3-0.2-3.6,0.5-5l5.9-7.9c0.5-0.7,0.8-1.6,0.8-2.5v-4.7c0-0.9-0.3-1.7-0.8-2.5
|
||||||
|
l-6.1-8.1c-0.9-1.2-0.8-3.5-0.2-4.9L22.8,33c0.8-1.3,3-2.1,4.5-2.1l9.9,1.2c0.9,0.1,1.7-0.1,2.6-0.6l4.1-2.3c0.7-0.5,1.3-1.2,1.7-2
|
||||||
|
l4-9.3c0.6-1.3,2.6-2.4,4.1-2.6H68c1.6,0,3.4,1.5,4.1,2.9l3.9,9.1c0.3,0.8,1,1.5,1.7,2l4.1,2.3c0.8,0.5,1.7,0.7,2.6,0.6l10.1-1.2
|
||||||
|
c1.5-0.2,3.3,1.1,4.3,2.2l7.3,12.4c0.8,1.3,0.2,3.6-0.5,5l-5.9,7.9c-0.6,0.7-0.8,1.6-0.8,2.5v4.7c0,0.9,0.2,1.8,0.8,2.5l2.6,3.5
|
||||||
|
h10.3c-0.1-0.1-0.2-0.2-0.2-0.3l-5.3-7v-1.9l5.3-7l0.8-1.2c2.3-4.1,2.3-8.8,0.1-12.7l-7.4-12.8l-0.8-1.2l-0.9-1.1
|
||||||
|
c-2.8-2.8-6.7-4.1-10.5-3.6l-8.7,1l-1.8-1l-3.4-8L79.1,13.5z M82.7,63.2c0,2.9-0.6,5.7-1.6,8.2h-9.5c1.8-2.3,2.9-5.1,2.9-8.2
|
||||||
|
c0-7.4-6-13.4-13.4-13.4s-13.3,5.9-13.3,13.4c0,7.3,5.8,13.2,13,13.3v8.2C49.1,84.6,39.6,75,39.6,63.2c0-12,9.7-21.6,21.5-21.6
|
||||||
|
C73.1,41.6,82.7,51.3,82.7,63.2z M126.9,83.8c0-2.3-1.9-4.1-4.1-4.1H73.2c-2.3,0-4.1,1.8-4.1,4.1c0,2.2,1.8,4.1,4.1,4.1h49.5
|
||||||
|
C125,88,126.9,86.1,126.9,83.8z M122.7,96.2c2.2,0,4.1,1.8,4.1,4.1c0,2.2-1.9,4.1-4.1,4.1H73.2c-2.3,0-4.1-1.9-4.1-4.1
|
||||||
|
c0-2.3,1.8-4.1,4.1-4.1H122.7z M126.9,116.8c0-2.3-1.9-4.1-4.1-4.1H73.2c-2.3,0-4.1,1.8-4.1,4.1c0,2.2,1.8,4.1,4.1,4.1h49.5
|
||||||
|
C125,121,126.9,119.1,126.9,116.8z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 2.2 KiB |
|
|
@ -26,7 +26,8 @@
|
||||||
"@opentiny/tiny-engine-common": "workspace:*",
|
"@opentiny/tiny-engine-common": "workspace:*",
|
||||||
"@opentiny/tiny-engine-meta-register": "workspace:*",
|
"@opentiny/tiny-engine-meta-register": "workspace:*",
|
||||||
"@opentiny/tiny-engine-utils": "workspace:*",
|
"@opentiny/tiny-engine-utils": "workspace:*",
|
||||||
"@vueuse/core": "^9.6.0"
|
"@vueuse/core": "^9.6.0",
|
||||||
|
"vue-draggable-next": "2.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opentiny/tiny-engine-vite-plugin-meta-comments": "workspace:*",
|
"@opentiny/tiny-engine-vite-plugin-meta-comments": "workspace:*",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,15 @@
|
||||||
|
<!-- 左侧插件栏-->
|
||||||
<template>
|
<template>
|
||||||
<div id="tiny-engine-nav-panel" :style="{ 'pointer-events': pluginState.pluginEvent }">
|
<div id="tiny-engine-nav-panel" :style="{ 'pointer-events': pluginState.pluginEvent }">
|
||||||
<ul class="nav-panel-lists top">
|
<vue-draggable-next
|
||||||
<li
|
v-model="state.topNavLists"
|
||||||
|
filter="EditorHelp"
|
||||||
|
class="nav-panel-lists top"
|
||||||
|
id="leftTop"
|
||||||
|
group="plugins"
|
||||||
|
@end="onEnd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
v-for="(item, index) in state.topNavLists"
|
v-for="(item, index) in state.topNavLists"
|
||||||
:key="index"
|
:key="index"
|
||||||
:class="{
|
:class="{
|
||||||
|
|
@ -12,8 +20,9 @@
|
||||||
}"
|
}"
|
||||||
:title="item.title"
|
:title="item.title"
|
||||||
@click="clickMenu({ item, index })"
|
@click="clickMenu({ item, index })"
|
||||||
|
@contextmenu.prevent="showContextMenu($event, true, item, index, PLUGIN_POSITION.leftTop)"
|
||||||
>
|
>
|
||||||
<div>
|
<div v-if="getPluginShown(item.id)">
|
||||||
<span class="item-icon">
|
<span class="item-icon">
|
||||||
<svg-icon
|
<svg-icon
|
||||||
v-if="typeof iconComponents[item.id] === 'string'"
|
v-if="typeof iconComponents[item.id] === 'string'"
|
||||||
|
|
@ -23,65 +32,80 @@
|
||||||
<component v-else :is="iconComponents[item.id]" class="panel-icon"></component>
|
<component v-else :is="iconComponents[item.id]" class="panel-icon"></component>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
</vue-draggable-next>
|
||||||
<ul class="nav-panel-lists bottom">
|
|
||||||
<li style="flex: 1" class="list-item"></li>
|
|
||||||
<li
|
|
||||||
v-for="(item, index) in state.bottomNavLists"
|
|
||||||
:key="index"
|
|
||||||
:class="[
|
|
||||||
'list-item',
|
|
||||||
{ active: renderPanel === item.id, prev: state.prevIdex - 1 === index, 'first-item': index === 0 }
|
|
||||||
]"
|
|
||||||
:title="item.title"
|
|
||||||
@click="clickMenu({ item, index })"
|
|
||||||
>
|
|
||||||
<div :class="{ 'is-show': renderPanel }">
|
|
||||||
<span class="item-icon">
|
|
||||||
<public-icon
|
|
||||||
v-if="typeof iconComponents[item.id] === 'string'"
|
|
||||||
:name="iconComponents[item.id]"
|
|
||||||
class="panel-icon"
|
|
||||||
svgClass="panel-svg"
|
|
||||||
></public-icon>
|
|
||||||
<component v-else :is="iconComponents[item.id]" class="panel-icon"></component>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<!-- 图标菜单下侧区域(附加icon) -->
|
||||||
v-show="renderPanel && components[renderPanel]"
|
<div class="nav-panel-lists bottom">
|
||||||
id="tiny-engine-left-panel"
|
<div style="flex: 1" class="list-item" @contextmenu.prevent="showContextMenu($event, false)" />
|
||||||
:class="[renderPanel, { 'is-fixed': pluginState.fixedPanels.includes(renderPanel) }]"
|
<vue-draggable-next id="leftBottom" v-model="state.bottomNavLists" group="plugins" @end="onEnd">
|
||||||
>
|
<div
|
||||||
<div class="left-panel-wrap">
|
v-for="(item, index) in state.bottomNavLists"
|
||||||
<keep-alive>
|
:key="index"
|
||||||
<component
|
:class="[
|
||||||
:is="components[renderPanel]"
|
'list-item',
|
||||||
ref="pluginRef"
|
{ active: renderPanel === item.id, prev: state.prevIdex - 1 === index, 'first-item': index === 0 }
|
||||||
:fixed-panels="pluginState.fixedPanels"
|
]"
|
||||||
@close="close"
|
:title="item.title"
|
||||||
@fixPanel="fixPanel"
|
@click="clickMenu({ item, index })"
|
||||||
></component>
|
@contextmenu.prevent="showContextMenu($event, true, item, index, PLUGIN_POSITION.leftBottom)"
|
||||||
</keep-alive>
|
>
|
||||||
|
<div :class="{ 'is-show': renderPanel }" v-if="getPluginShown(item.id)">
|
||||||
|
<span class="item-icon">
|
||||||
|
<public-icon
|
||||||
|
v-if="typeof iconComponents[item.id] === 'string'"
|
||||||
|
:name="iconComponents[item.id]"
|
||||||
|
class="panel-icon"
|
||||||
|
svgClass="panel-svg"
|
||||||
|
></public-icon>
|
||||||
|
<component v-else :is="iconComponents[item.id]" class="panel-icon"></component>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</vue-draggable-next>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div :class="{ 'not-selected': getMoveDragBarState() }">
|
||||||
|
<!-- 插件面板 -->
|
||||||
|
<div
|
||||||
|
v-show="renderPanel && components[renderPanel]"
|
||||||
|
id="tiny-engine-left-panel"
|
||||||
|
:class="[renderPanel, { 'is-fixed': leftFixedPanelsStorage.includes(renderPanel) }]"
|
||||||
|
>
|
||||||
|
<div class="left-panel-wrap">
|
||||||
|
<keep-alive>
|
||||||
|
<component
|
||||||
|
ref="pluginRef"
|
||||||
|
:is="currentComponent"
|
||||||
|
:fixed-panels="leftFixedPanelsStorage"
|
||||||
|
@close="close"
|
||||||
|
@fixPanel="fixPanel"
|
||||||
|
></component>
|
||||||
|
</keep-alive>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<plugin-right-menu
|
||||||
|
ref="rightMenu"
|
||||||
|
:list="[...state.topNavLists, ...state.bottomNavLists]"
|
||||||
|
:align="left"
|
||||||
|
@switchAlign="switchAlign"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reactive, ref, watch } from 'vue'
|
import { reactive, ref, watch, computed } from 'vue'
|
||||||
import { Popover, Tooltip } from '@opentiny/vue'
|
import { Popover, Tooltip } from '@opentiny/vue'
|
||||||
import { useLayout, usePage, useModal, META_APP } from '@opentiny/tiny-engine-meta-register'
|
import { VueDraggableNext } from 'vue-draggable-next'
|
||||||
import { PublicIcon } from '@opentiny/tiny-engine-common'
|
import { useLayout, usePage, META_APP } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { constants } from '@opentiny/tiny-engine-utils'
|
import { PublicIcon, PluginRightMenu } from '@opentiny/tiny-engine-common'
|
||||||
|
|
||||||
const { STORAGE_KEY_FIXED_PANELS } = constants
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
PluginRightMenu,
|
||||||
|
VueDraggableNext,
|
||||||
TinyPopover: Popover,
|
TinyPopover: Popover,
|
||||||
TinyTooltip: Tooltip,
|
TinyTooltip: Tooltip,
|
||||||
PublicIcon
|
PublicIcon
|
||||||
|
|
@ -93,6 +117,10 @@ export default {
|
||||||
plugins: {
|
plugins: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
},
|
||||||
|
pluginList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['click', 'node-click'],
|
emits: ['click', 'node-click'],
|
||||||
|
|
@ -101,18 +129,56 @@ export default {
|
||||||
const iconComponents = {}
|
const iconComponents = {}
|
||||||
const pluginRef = ref(null)
|
const pluginRef = ref(null)
|
||||||
const { isTemporaryPage } = usePage()
|
const { isTemporaryPage } = usePage()
|
||||||
const { message } = useModal()
|
|
||||||
const pluginState = useLayout().getPluginState()
|
const pluginState = useLayout().getPluginState()
|
||||||
|
|
||||||
props.plugins.forEach(({ id, entry, icon }) => {
|
const {
|
||||||
|
changeLeftFixedPanels,
|
||||||
|
leftFixedPanelsStorage,
|
||||||
|
getPluginById,
|
||||||
|
getPluginShown,
|
||||||
|
PLUGIN_POSITION,
|
||||||
|
getMoveDragBarState,
|
||||||
|
isSameSide,
|
||||||
|
dragPluginLayout,
|
||||||
|
getPluginsByPosition
|
||||||
|
} = useLayout()
|
||||||
|
|
||||||
|
const rightMenu = ref(null)
|
||||||
|
const showContextMenu = (event, type, item, index, align) => {
|
||||||
|
if (!type) {
|
||||||
|
rightMenu.value.showContextMenu(event.clientX, event.clientY, type)
|
||||||
|
} else {
|
||||||
|
rightMenu.value.showContextMenu(event.clientX, event.clientY, type, item, index, align)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
prevIdex: -2,
|
||||||
|
topNavLists: getPluginsByPosition(PLUGIN_POSITION.leftTop, props.pluginList),
|
||||||
|
bottomNavLists: getPluginsByPosition(PLUGIN_POSITION.leftBottom, props.pluginList)
|
||||||
|
})
|
||||||
|
|
||||||
|
const changeAlign = (pluginId) => {
|
||||||
|
const item = getPluginById(props.pluginList, pluginId)
|
||||||
|
const existingItemIndex = state.topNavLists.findIndex((plugin) => plugin.id === item.id)
|
||||||
|
|
||||||
|
if (existingItemIndex !== -1) {
|
||||||
|
state.topNavLists.splice(existingItemIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.topNavLists.unshift(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
props.pluginList.forEach(({ id, entry, icon }) => {
|
||||||
components[id] = entry
|
components[id] = entry
|
||||||
iconComponents[id] = icon
|
iconComponents[id] = icon
|
||||||
})
|
})
|
||||||
|
|
||||||
const state = reactive({
|
const currentComponent = computed(() => {
|
||||||
prevIdex: -2,
|
const isExistedComponent = [...state.topNavLists, ...state.bottomNavLists].some(
|
||||||
topNavLists: props.plugins.filter((item) => item.align === 'top'),
|
(item) => item.id === props.renderPanel
|
||||||
bottomNavLists: props.plugins.filter((item) => item.align === 'bottom')
|
)
|
||||||
|
return isExistedComponent ? components[props.renderPanel] : null
|
||||||
})
|
})
|
||||||
|
|
||||||
const clickMenu = ({ item, index }) => {
|
const clickMenu = ({ item, index }) => {
|
||||||
|
|
@ -127,14 +193,14 @@ export default {
|
||||||
result &&
|
result &&
|
||||||
emit('click', {
|
emit('click', {
|
||||||
item,
|
item,
|
||||||
navLists: item.align === 'top' ? state.topNavLists[index] : state.bottomNavLists[index]
|
navLists: item.align === 'leftTop' ? state.topNavLists[index] : state.bottomNavLists[index]
|
||||||
})
|
})
|
||||||
|
|
||||||
pluginRef.value?.[lastPlugin.confirm](confirmCallback)
|
pluginRef.value?.[lastPlugin.confirm](confirmCallback)
|
||||||
} else {
|
} else {
|
||||||
emit('click', {
|
emit('click', {
|
||||||
item,
|
item,
|
||||||
navLists: item.align === 'top' ? state.topNavLists[index] : state.bottomNavLists[index]
|
navLists: item.align === 'leftTop' ? state.topNavLists[index] : state.bottomNavLists[index]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -154,35 +220,43 @@ export default {
|
||||||
useLayout().closePlugin(true)
|
useLayout().closePlugin(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param index 组件索引
|
||||||
|
* @param id 组件 ID, 类似于 'engine.plugins.*'
|
||||||
|
* @param from 组件来源
|
||||||
|
*/
|
||||||
|
const switchAlign = (index, id, from) => {
|
||||||
|
if (from === PLUGIN_POSITION.leftTop) {
|
||||||
|
state.topNavLists.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
state.bottomNavLists.splice(index, 1)
|
||||||
|
}
|
||||||
|
emit('changeLeftAlign', id)
|
||||||
|
|
||||||
|
if (!isSameSide(index, 0)) close()
|
||||||
|
dragPluginLayout(from, PLUGIN_POSITION.rightTop, index, 0)
|
||||||
|
}
|
||||||
|
|
||||||
const fixPanel = (pluginName) => {
|
const fixPanel = (pluginName) => {
|
||||||
pluginState.fixedPanels = pluginState.fixedPanels?.includes(pluginName)
|
changeLeftFixedPanels(pluginName)
|
||||||
? pluginState.fixedPanels?.filter((item) => item !== pluginName)
|
|
||||||
: [...pluginState.fixedPanels, pluginName]
|
|
||||||
|
|
||||||
try {
|
|
||||||
localStorage.setItem(STORAGE_KEY_FIXED_PANELS, JSON.stringify(pluginState.fixedPanels))
|
|
||||||
} catch (error) {
|
|
||||||
message({ message: `'存储固定面板数据失败:'${error}`, status: 'error' })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const restoreFixedPanels = () => {
|
//监听拖拽结束事件
|
||||||
try {
|
const onEnd = (e) => {
|
||||||
const storedPanels = localStorage.getItem(STORAGE_KEY_FIXED_PANELS)
|
if (!isSameSide(e.from.id, e.to.id)) close()
|
||||||
pluginState.fixedPanels = storedPanels ? JSON.parse(storedPanels) : []
|
dragPluginLayout(e.from.id, e.to.id, e.oldIndex, e.newIndex)
|
||||||
|
|
||||||
if (!Array.isArray(pluginState.fixedPanels)) {
|
|
||||||
pluginState.fixedPanels = []
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
message({ message: `'读取固定面板数据失败:'${error}`, status: 'error' })
|
|
||||||
pluginState.fixedPanels = []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreFixedPanels()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
leftFixedPanelsStorage,
|
||||||
|
currentComponent,
|
||||||
|
changeAlign,
|
||||||
|
rightMenu,
|
||||||
|
PLUGIN_POSITION,
|
||||||
|
showContextMenu,
|
||||||
|
switchAlign,
|
||||||
|
getPluginShown,
|
||||||
|
onEnd,
|
||||||
state,
|
state,
|
||||||
clickMenu,
|
clickMenu,
|
||||||
pluginRef,
|
pluginRef,
|
||||||
|
|
@ -190,6 +264,7 @@ export default {
|
||||||
fixPanel,
|
fixPanel,
|
||||||
pluginState,
|
pluginState,
|
||||||
components,
|
components,
|
||||||
|
getMoveDragBarState,
|
||||||
iconComponents
|
iconComponents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +273,7 @@ export default {
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
#tiny-engine-left-panel {
|
#tiny-engine-left-panel {
|
||||||
width: var(--base-left-panel-width);
|
width: auto !important;
|
||||||
height: calc(100vh - var(--base-top-panel-height));
|
height: calc(100vh - var(--base-top-panel-height));
|
||||||
border-right: 1px solid var(--te-layout-common-border-color);
|
border-right: 1px solid var(--te-layout-common-border-color);
|
||||||
background: var(--te-layout-common-bg-color);
|
background: var(--te-layout-common-bg-color);
|
||||||
|
|
@ -209,10 +284,6 @@ export default {
|
||||||
left: var(--base-nav-panel-width);
|
left: var(--base-nav-panel-width);
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
|
||||||
&[class~='engine.plugins.i18n'] {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-fixed {
|
&.is-fixed {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
@ -324,4 +395,9 @@ export default {
|
||||||
:deep(.svg-icon.icon-plugin-icon-plugin-help) {
|
:deep(.svg-icon.icon-plugin-icon-plugin-help) {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.not-selected {
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,130 +1,328 @@
|
||||||
|
<!-- 右侧插件栏 -->
|
||||||
<template>
|
<template>
|
||||||
<div id="tiny-right-panel">
|
<div :class="{ 'not-selected': getMoveDragBarState() }">
|
||||||
<tiny-tabs v-model="layoutState.settings.render">
|
<div
|
||||||
<tiny-tab-item v-for="(setting, index) in settings" :key="index" :title="setting.title" :name="setting.name">
|
v-show="renderPanel && components[renderPanel]"
|
||||||
<component :is="setting.entry"></component>
|
id="tiny-engine-right-panel"
|
||||||
<div v-show="activating" class="active"></div>
|
:class="[renderPanel, { 'is-fixed': rightFixedPanelsStorage.includes(renderPanel) }]"
|
||||||
</tiny-tab-item>
|
>
|
||||||
</tiny-tabs>
|
<div class="right-panel-wrap">
|
||||||
<div v-if="layoutState.settings.render === 'style'" class="tabs-setting">
|
<component
|
||||||
<tiny-tooltip effect="light" :content="isCollapsed ? '展开' : '折叠'" placement="top" :visible-arrow="false">
|
:is="currentComponent"
|
||||||
<template #default> <svg-icon :name="settingIcon" @click="isCollapsed = !isCollapsed"></svg-icon> </template>
|
:fixed-panels="rightFixedPanelsStorage"
|
||||||
</tiny-tooltip>
|
@close="close"
|
||||||
|
@fixPanel="fixPanel"
|
||||||
|
></component>
|
||||||
|
<div v-show="activating" class="active2" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="tiny-engine-nav-panel">
|
||||||
|
<vue-draggable-next id="rightTop" v-model="settingPlugins" class="nav-panel-lists" group="plugins" @end="onEnd">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in settingPlugins"
|
||||||
|
:key="index"
|
||||||
|
:class="['list-item', { 'first-item': item === settingPlugins[0], active: item.id === renderPanel }]"
|
||||||
|
:title="item.title"
|
||||||
|
@click="clickMenu({ item, index })"
|
||||||
|
@contextmenu.prevent="showContextMenu($event, true, item, index, PLUGIN_POSITION.rightTop)"
|
||||||
|
>
|
||||||
|
<span class="item-icon" v-if="getPluginShown(item.id)">
|
||||||
|
<svg-icon v-if="iconComponents[item.id]" :name="iconComponents[item.id]" class="panel-icon"></svg-icon>
|
||||||
|
<component v-else :is="iconComponents[item.id]" class="panel-icon"></component>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1" class="list-item" @contextmenu.prevent="showContextMenu($event, false)"></div>
|
||||||
|
</vue-draggable-next>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<plugin-right-menu
|
||||||
|
ref="rightMenu"
|
||||||
|
:list="settingPlugins"
|
||||||
|
:align="PLUGIN_POSITION.rightTop"
|
||||||
|
@switchAlign="switchAlign"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed, provide, ref } from 'vue'
|
import { computed, ref, watch, toRefs } from 'vue'
|
||||||
import { Tabs, TabItem, Tooltip } from '@opentiny/vue'
|
import { Tabs, TabItem } from '@opentiny/vue'
|
||||||
import { useLayout } from '@opentiny/tiny-engine-meta-register'
|
import { useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
|
import { VueDraggableNext } from 'vue-draggable-next'
|
||||||
|
import { PluginRightMenu } from '@opentiny/tiny-engine-common'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
PluginRightMenu,
|
||||||
TinyTabs: Tabs,
|
TinyTabs: Tabs,
|
||||||
TinyTabItem: TabItem,
|
TinyTabItem: TabItem,
|
||||||
TinyTooltip: Tooltip
|
VueDraggableNext
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
settings: {
|
settings: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
},
|
||||||
|
renderPanel: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
pluginList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup() {
|
setup(props, { emit }) {
|
||||||
const { layoutState } = useLayout()
|
const components = {}
|
||||||
const activating = computed(() => layoutState.settings.activating)
|
const iconComponents = {}
|
||||||
const showMask = ref(true)
|
|
||||||
const isCollapsed = ref(false)
|
|
||||||
const settingIcon = computed(() => (isCollapsed.value ? 'collapse_all' : 'expand_all'))
|
|
||||||
|
|
||||||
provide('isCollapsed', isCollapsed)
|
const {
|
||||||
|
getPluginsByPosition,
|
||||||
|
getPluginById,
|
||||||
|
PLUGIN_POSITION,
|
||||||
|
rightFixedPanelsStorage,
|
||||||
|
changeRightFixedPanels,
|
||||||
|
dragPluginLayout,
|
||||||
|
isSameSide,
|
||||||
|
getPluginShown,
|
||||||
|
getMoveDragBarState,
|
||||||
|
layoutState: { settings: settingsState }
|
||||||
|
} = useLayout()
|
||||||
|
|
||||||
|
const rightMenu = ref(null)
|
||||||
|
const { renderPanel } = toRefs(props)
|
||||||
|
const showContextMenu = (event, type, item, index, align) => {
|
||||||
|
if (!type) {
|
||||||
|
rightMenu.value.showContextMenu(event.clientX, event.clientY, type)
|
||||||
|
} else {
|
||||||
|
rightMenu.value.showContextMenu(event.clientX, event.clientY, type, item, index, align)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
props.pluginList.forEach(({ id, entry, icon }) => {
|
||||||
|
components[id] = entry
|
||||||
|
iconComponents[id] = icon
|
||||||
|
})
|
||||||
|
|
||||||
|
const settingPlugins = ref(getPluginsByPosition(PLUGIN_POSITION.rightTop, props.pluginList))
|
||||||
|
|
||||||
|
const currentComponent = computed(() => {
|
||||||
|
const isExistedComponent = settingPlugins.value.some((item) => item.id === renderPanel.value)
|
||||||
|
return isExistedComponent ? components[renderPanel.value] : null
|
||||||
|
})
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
useLayout().closeSetting(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const switchAlign = (index, id, from) => {
|
||||||
|
settingPlugins.value.splice(index, 1)
|
||||||
|
emit('changeRightAlign', id)
|
||||||
|
if (!isSameSide(index, 0)) close()
|
||||||
|
dragPluginLayout(from, PLUGIN_POSITION.leftTop, index, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeAlign = (pluginId) => {
|
||||||
|
const item = getPluginById(props.pluginList, pluginId)
|
||||||
|
const existingItemIndex = settingPlugins.value.findIndex((plugin) => plugin.id === item.id)
|
||||||
|
|
||||||
|
if (existingItemIndex !== -1) {
|
||||||
|
settingPlugins.value.splice(existingItemIndex, 1)
|
||||||
|
}
|
||||||
|
settingPlugins.value.unshift(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
const setRender = (curId) => {
|
||||||
|
settingsState.render = curId
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击右侧菜单icon按钮
|
||||||
|
const clickMenu = ({ item }) => {
|
||||||
|
if (settingsState.render == item.id) {
|
||||||
|
useLayout().closeSetting(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setRender(item.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(renderPanel, (n) => {
|
||||||
|
setRender(n)
|
||||||
|
})
|
||||||
|
|
||||||
|
//切换面板状态
|
||||||
|
const fixPanel = (pluginName) => {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
const activating = computed(() => settingsState.activating)
|
||||||
|
const showMask = ref(true)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
currentComponent,
|
||||||
|
changeAlign,
|
||||||
showMask,
|
showMask,
|
||||||
isCollapsed,
|
|
||||||
activating,
|
activating,
|
||||||
settingIcon,
|
settingsState,
|
||||||
layoutState
|
settingPlugins,
|
||||||
|
components,
|
||||||
|
iconComponents,
|
||||||
|
clickMenu,
|
||||||
|
close,
|
||||||
|
fixPanel,
|
||||||
|
rightFixedPanelsStorage,
|
||||||
|
onEnd,
|
||||||
|
showContextMenu,
|
||||||
|
PLUGIN_POSITION,
|
||||||
|
getPluginShown,
|
||||||
|
switchAlign,
|
||||||
|
rightMenu,
|
||||||
|
getMoveDragBarState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
#tiny-right-panel {
|
#tiny-engine-right-panel {
|
||||||
width: var(--base-right-panel-width);
|
height: calc(100vh - var(--base-top-panel-height));
|
||||||
height: 100%;
|
|
||||||
transition: 0.3s linear;
|
|
||||||
position: relative;
|
|
||||||
border-left: 1px solid var(--te-layout-common-border-color);
|
border-left: 1px solid var(--te-layout-common-border-color);
|
||||||
padding-top: 12px;
|
background: var(--ti-lowcode-common-component-bg);
|
||||||
background-color: var(--te-layout-common-bg-color);
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
top: var(--base-top-panel-height);
|
||||||
|
right: var(--base-nav-panel-width);
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
.tabs-setting {
|
&.I18n {
|
||||||
position: absolute;
|
width: auto;
|
||||||
top: 9px;
|
|
||||||
right: 18px;
|
|
||||||
line-height: 26px;
|
|
||||||
color: var(--te-layout-common-icon-color);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
.tiny-tabs {
|
|
||||||
|
&.is-fixed {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel-wrap {
|
||||||
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
position: relative;
|
||||||
:deep(.tiny-tabs) {
|
:deep(.tiny-tabs__nav.is-show-active-bar) .tiny-tabs__item {
|
||||||
display: flex;
|
margin-right: 0;
|
||||||
flex-direction: column;
|
|
||||||
.tiny-tabs__header .tiny-tabs__nav {
|
|
||||||
width: 60%;
|
|
||||||
background-color: var(--te-layout-common-bg-color);
|
|
||||||
}
|
}
|
||||||
.tiny-tabs__nav-scroll {
|
|
||||||
margin-left: 12px;
|
|
||||||
.tiny-tabs__active-bar {
|
|
||||||
height: 3px;
|
|
||||||
background-color: var(--te-layout-common-text-color-active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tiny-tabs__content {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.tiny-tabs__nav.is-show-active-bar .tiny-tabs__item {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
.tiny-tabs__item {
|
|
||||||
flex: 1;
|
|
||||||
background-color: var(--te-layout-common-bg-color);
|
|
||||||
color: var(--te-layout-common-text-color-secondary);
|
|
||||||
margin-right: 5px;
|
|
||||||
&:hover {
|
|
||||||
color: var(--te-layout-common-text-color-hover);
|
|
||||||
}
|
|
||||||
&.is-active {
|
|
||||||
color: var(--te-layout-common-text-color-active);
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tiny-tabs__item__title {
|
|
||||||
padding-bottom: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tiny-tabs__nav-wrap-not-separator::after {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.tiny-collapse-item__content) {
|
|
||||||
padding: 0 8px 12px 12px; // 这里的bottom为4px + 内部行元素与底部的距离为8px = 12px
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
#tiny-engine-nav-panel {
|
||||||
|
display: none;
|
||||||
|
width: var(--base-nav-panel-width);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: var(--te-layout-common-bg-color);
|
||||||
|
box-sizing: border-box;
|
||||||
|
z-index: 1000;
|
||||||
|
border-left: 1px solid var(--te-layout-common-border-color);
|
||||||
|
|
||||||
|
&.completed {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-panel-lists {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
&.bottom {
|
||||||
|
flex: 1;
|
||||||
|
padding-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
width: 100%;
|
||||||
|
padding: 3px 0;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.active {
|
||||||
|
.item-icon {
|
||||||
|
background: var(--te-layout-common-bg-color-hover);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
color: var(--te-layout-common-text-color-secondary-checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.prev {
|
||||||
|
border-bottom-color: var(--te-layout-common-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--te-layout-common-text-color);
|
||||||
|
font-size: 22px;
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.public-icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.panel-svg) {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.svg-icon.icon-plugin-icon-plugin-help) {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.not-selected {
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.svg-icon.icon-plugin-icon-plugin-help) {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
//高亮显示动画
|
||||||
|
.active2 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -135,10 +333,10 @@ export default {
|
||||||
|
|
||||||
@keyframes glow {
|
@keyframes glow {
|
||||||
0% {
|
0% {
|
||||||
box-shadow: inset 0px 0px 4px var(--te-layout-setting-bg-color-hover);
|
box-shadow: inset 0px 0px 4px var(--ti-lowcode-canvas-handle-hover-bg);
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
box-shadow: inset 0px 0px 14px var(--te-layout-setting-bg-color-hover);
|
box-shadow: inset 0px 0px 14px var(--ti-lowcode-canvas-handle-hover-bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,12 @@
|
||||||
<div class="tiny-engine-left-wrap">
|
<div class="tiny-engine-left-wrap">
|
||||||
<div class="tiny-engine-content-wrap">
|
<div class="tiny-engine-content-wrap">
|
||||||
<design-plugins
|
<design-plugins
|
||||||
|
v-if="leftMenuShownStorage"
|
||||||
|
ref="left"
|
||||||
:plugins="registry.plugins"
|
:plugins="registry.plugins"
|
||||||
|
:plugin-list="pluginList"
|
||||||
:render-panel="plugins.render"
|
:render-panel="plugins.render"
|
||||||
|
@changeLeftAlign="changeLeftAlign"
|
||||||
@click="toggleNav"
|
@click="toggleNav"
|
||||||
></design-plugins>
|
></design-plugins>
|
||||||
<component :is="registry.canvas.entry"></component>
|
<component :is="registry.canvas.entry"></component>
|
||||||
|
|
@ -15,9 +19,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="tiny-engine-right-wrap">
|
<div class="tiny-engine-right-wrap">
|
||||||
<design-settings
|
<design-settings
|
||||||
:settings="registry.settings"
|
v-if="rightMenuShownStorage"
|
||||||
v-show="layoutState.settings.showDesignSettings"
|
|
||||||
ref="right"
|
ref="right"
|
||||||
|
:settings="registry.settings"
|
||||||
|
:render-panel="settings.render"
|
||||||
|
:plugin-list="pluginList"
|
||||||
|
v-show="layoutState.settings.showDesignSettings"
|
||||||
|
@changeRightAlign="changeRightAlign"
|
||||||
></design-settings>
|
></design-settings>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -27,10 +35,12 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useLayout, getMergeRegistry } from '@opentiny/tiny-engine-meta-register'
|
import { useLayout, getMergeRegistry } from '@opentiny/tiny-engine-meta-register'
|
||||||
|
import { constants } from '@opentiny/tiny-engine-utils'
|
||||||
import DesignToolbars from './DesignToolbars.vue'
|
import DesignToolbars from './DesignToolbars.vue'
|
||||||
import DesignPlugins from './DesignPlugins.vue'
|
import DesignPlugins from './DesignPlugins.vue'
|
||||||
import DesignSettings from './DesignSettings.vue'
|
import DesignSettings from './DesignSettings.vue'
|
||||||
import meta from '../meta'
|
import meta from '../meta'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TinyLowCode',
|
name: 'TinyLowCode',
|
||||||
|
|
@ -49,24 +59,82 @@ export default {
|
||||||
type: Object
|
type: Object
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup() {
|
setup(props) {
|
||||||
const layoutRegistry = getMergeRegistry(meta.type)
|
const layoutRegistry = getMergeRegistry(meta.type)
|
||||||
const configProvider = layoutRegistry.options.configProvider
|
const configProvider = layoutRegistry.options.configProvider
|
||||||
const configProviderDesign = layoutRegistry.options.configProviderDesign
|
const configProviderDesign = layoutRegistry.options.configProviderDesign
|
||||||
|
|
||||||
const { layoutState } = useLayout()
|
const { layoutState, leftMenuShownStorage, rightMenuShownStorage, initPluginStorageReactive } = useLayout()
|
||||||
const { plugins } = layoutState
|
const { plugins, settings } = layoutState
|
||||||
|
|
||||||
const toggleNav = ({ item }) => {
|
const toggleNav = ({ item }) => {
|
||||||
if (!item.id) return
|
if (!item.id) return
|
||||||
plugins.render = plugins.render === item.id ? null : item.id
|
plugins.render = plugins.render === item.id ? null : item.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const left = ref(null)
|
||||||
|
const right = ref(null)
|
||||||
|
|
||||||
|
const changeLeftAlign = (pluginId) => {
|
||||||
|
right.value?.changeAlign(pluginId)
|
||||||
|
}
|
||||||
|
const changeRightAlign = (pluginId) => {
|
||||||
|
left.value?.changeAlign(pluginId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并插件和设置列表
|
||||||
|
const pluginList = [...props.registry.plugins, ...props.registry.settings]
|
||||||
|
|
||||||
|
// 收集插件的 align 信息
|
||||||
|
const alignGroups = {}
|
||||||
|
const plugin = {}
|
||||||
|
|
||||||
|
const { PLUGIN_DEFAULT_WIDTH } = constants
|
||||||
|
|
||||||
|
pluginList.forEach((item) => {
|
||||||
|
if (item.id) {
|
||||||
|
const align = item?.align || 'leftTop'
|
||||||
|
|
||||||
|
// 初始化 alignGroups[align]
|
||||||
|
if (!alignGroups[align]) {
|
||||||
|
alignGroups[align] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 item.id 推入对应的 alignGroups
|
||||||
|
alignGroups[align].push(item.id)
|
||||||
|
|
||||||
|
// 为每个插件分配 index 和相关属性
|
||||||
|
const index = alignGroups[align].indexOf(item.id)
|
||||||
|
const widthResizable = item?.widthResizable ?? false
|
||||||
|
|
||||||
|
plugin[item.id] = {
|
||||||
|
width: item?.width || PLUGIN_DEFAULT_WIDTH,
|
||||||
|
align: align,
|
||||||
|
index: index,
|
||||||
|
isShow: true,
|
||||||
|
entry: item.entry,
|
||||||
|
id: item.id,
|
||||||
|
icon: item.icon,
|
||||||
|
widthResizable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
localStorage.setItem('plugin', JSON.stringify(plugin))
|
||||||
|
initPluginStorageReactive(plugin)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
changeLeftAlign,
|
||||||
|
changeRightAlign,
|
||||||
|
leftMenuShownStorage,
|
||||||
|
rightMenuShownStorage,
|
||||||
|
pluginList,
|
||||||
layoutRegistry,
|
layoutRegistry,
|
||||||
configProvider,
|
configProvider,
|
||||||
configProviderDesign,
|
configProviderDesign,
|
||||||
plugins,
|
plugins,
|
||||||
|
settings,
|
||||||
toggleNav,
|
toggleNav,
|
||||||
layoutState
|
layoutState
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +166,8 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tiny-engine-right-wrap {
|
.tiny-engine-right-wrap {
|
||||||
position: relative;
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
:deep(.monaco-editor .suggest-widget) {
|
:deep(.monaco-editor .suggest-widget) {
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,27 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { reactive, nextTick } from 'vue'
|
import { reactive, nextTick } from 'vue'
|
||||||
|
import { useStorage } from '@vueuse/core'
|
||||||
import { constants } from '@opentiny/tiny-engine-utils'
|
import { constants } from '@opentiny/tiny-engine-utils'
|
||||||
import { META_APP as PLUGIN_NAME, getMetaApi } from '@opentiny/tiny-engine-meta-register'
|
import { META_APP as PLUGIN_NAME, getMetaApi } from '@opentiny/tiny-engine-meta-register'
|
||||||
|
|
||||||
const { PAGE_STATUS } = constants
|
const { PAGE_STATUS, STORAGE_KEY_LEFT_FIXED_PANELS, STORAGE_KEY_RIGHT_FIXED_PANELS, PLUGIN_DEFAULT_WIDTH } = constants
|
||||||
|
|
||||||
|
const PLUGIN_POSITION = {
|
||||||
|
leftTop: 'leftTop',
|
||||||
|
leftBottom: 'leftBottom',
|
||||||
|
independence: 'independence',
|
||||||
|
rightTop: 'rightTop',
|
||||||
|
rightBottom: 'rightBottom',
|
||||||
|
fixed: 'fixed'
|
||||||
|
}
|
||||||
|
|
||||||
|
const pluginState = reactive({
|
||||||
|
pluginEvent: 'all'
|
||||||
|
})
|
||||||
|
|
||||||
const layoutState = reactive({
|
const layoutState = reactive({
|
||||||
|
isMoveDragBar: false,
|
||||||
dimension: {
|
dimension: {
|
||||||
deviceType: 'desktop',
|
deviceType: 'desktop',
|
||||||
width: '',
|
width: '',
|
||||||
|
|
@ -26,12 +41,17 @@ const layoutState = reactive({
|
||||||
height: '100%'
|
height: '100%'
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
|
isShow: true,
|
||||||
fixedPanels: [PLUGIN_NAME.Materials],
|
fixedPanels: [PLUGIN_NAME.Materials],
|
||||||
render: null,
|
render: PLUGIN_NAME.Materials,
|
||||||
pluginEvent: 'all'
|
pluginEvent: 'all',
|
||||||
|
activating: false, // 右侧面版激活提示状态
|
||||||
|
showDesignSettings: true
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
render: 'props',
|
isShow: true,
|
||||||
|
fixedPanels: [PLUGIN_NAME.Props, PLUGIN_NAME.Styles, PLUGIN_NAME.Event],
|
||||||
|
render: PLUGIN_NAME.Props,
|
||||||
api: null,
|
api: null,
|
||||||
activating: false, // 右侧面版激活提示状态
|
activating: false, // 右侧面版激活提示状态
|
||||||
showDesignSettings: true
|
showDesignSettings: true
|
||||||
|
|
@ -41,10 +61,44 @@ const layoutState = reactive({
|
||||||
},
|
},
|
||||||
pageStatus: ''
|
pageStatus: ''
|
||||||
})
|
})
|
||||||
|
const getMoveDragBarState = () => {
|
||||||
|
return layoutState.isMoveDragBar
|
||||||
|
}
|
||||||
|
const changeMoveDragBarState = (state) => {
|
||||||
|
layoutState.isMoveDragBar = state
|
||||||
|
}
|
||||||
|
const leftMenuShownStorage = useStorage('leftMenuShown', layoutState.plugins.isShow)
|
||||||
|
const rightMenuShownStorage = useStorage('rightMenuShown', layoutState.settings.isShow)
|
||||||
|
const changeMenuShown = (menuName) => {
|
||||||
|
switch (menuName) {
|
||||||
|
case 'left': {
|
||||||
|
leftMenuShownStorage.value = !leftMenuShownStorage.value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'right': {
|
||||||
|
rightMenuShownStorage.value = !rightMenuShownStorage.value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const leftFixedPanelsStorage = useStorage(STORAGE_KEY_LEFT_FIXED_PANELS, layoutState.plugins.fixedPanels)
|
||||||
|
const rightFixedPanelsStorage = useStorage(STORAGE_KEY_RIGHT_FIXED_PANELS, layoutState.settings.fixedPanels)
|
||||||
|
|
||||||
|
const changeLeftFixedPanels = (pluginName) => {
|
||||||
|
leftFixedPanelsStorage.value = leftFixedPanelsStorage.value?.includes(pluginName)
|
||||||
|
? leftFixedPanelsStorage.value?.filter((item) => item !== pluginName)
|
||||||
|
: [...leftFixedPanelsStorage.value, pluginName]
|
||||||
|
}
|
||||||
|
const changeRightFixedPanels = (pluginName) => {
|
||||||
|
rightFixedPanelsStorage.value = rightFixedPanelsStorage.value?.includes(pluginName)
|
||||||
|
? rightFixedPanelsStorage.value?.filter((item) => item !== pluginName)
|
||||||
|
: [...rightFixedPanelsStorage.value, pluginName]
|
||||||
|
}
|
||||||
|
|
||||||
const getScale = () => layoutState.dimension.scale
|
const getScale = () => layoutState.dimension.scale
|
||||||
|
|
||||||
const getPluginState = () => layoutState.plugins
|
const getPluginState = () => layoutState.plugins
|
||||||
|
const getSettingState = () => layoutState.settings
|
||||||
|
|
||||||
const getDimension = () => layoutState.dimension
|
const getDimension = () => layoutState.dimension
|
||||||
|
|
||||||
|
|
@ -66,6 +120,22 @@ const activeSetting = (name) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 两侧面板的固定状态
|
||||||
|
*/
|
||||||
|
const getFixedPanelsStatus = () => {
|
||||||
|
const leftPanelFixed = leftFixedPanelsStorage.value.includes(layoutState.plugins.render)
|
||||||
|
const rightPanelFixed = rightFixedPanelsStorage.value.includes(layoutState.settings.render)
|
||||||
|
return { leftPanelFixed, rightPanelFixed }
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeSetting = (forceClose) => {
|
||||||
|
const { settings } = layoutState
|
||||||
|
if (!settings.fixedPanels.includes(settings.render) || forceClose) {
|
||||||
|
settings.render = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 激活plugin面板并返回当前插件注册的Api
|
// 激活plugin面板并返回当前插件注册的Api
|
||||||
const activePlugin = (name, noActiveRender) => {
|
const activePlugin = (name, noActiveRender) => {
|
||||||
const { plugins } = layoutState
|
const { plugins } = layoutState
|
||||||
|
|
@ -90,16 +160,191 @@ const closePlugin = (forceClose) => {
|
||||||
const isEmptyPage = () => layoutState.pageStatus?.state === PAGE_STATUS.Empty
|
const isEmptyPage = () => layoutState.pageStatus?.state === PAGE_STATUS.Empty
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
let plugin = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const storedPlugin = localStorage.getItem('plugin')
|
||||||
|
if (storedPlugin) {
|
||||||
|
plugin = JSON.parse(storedPlugin)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 plugin 不是一个数组,则将其重置为默认值
|
||||||
|
if (!Array.isArray(plugin)) {
|
||||||
|
plugin = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const pluginStorageReactive = useStorage('plugin', plugin)
|
||||||
|
|
||||||
|
// 获取插件宽度
|
||||||
|
const getPluginWidth = (name) => pluginStorageReactive.value[name]?.width || PLUGIN_DEFAULT_WIDTH
|
||||||
|
|
||||||
|
// 修改插件宽度
|
||||||
|
const changePluginWidth = (name, width, offset) => {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(pluginStorageReactive.value, name)) {
|
||||||
|
pluginStorageReactive.value[name].width = width
|
||||||
|
pluginStorageReactive.value[name].offset = offset
|
||||||
|
} else {
|
||||||
|
pluginStorageReactive.value[name] = {
|
||||||
|
width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取插件布局
|
||||||
|
const getPluginByLayout = (name) => pluginStorageReactive.value[name]?.align || 'leftTop'
|
||||||
|
|
||||||
|
// 获取某个布局(左上/左下/右上/右下)的插件名称列表
|
||||||
|
const getPluginsByLayout = (layout = 'all') => {
|
||||||
|
// 筛选出符合布局条件的插件名称
|
||||||
|
const pluginNames = Object.keys(pluginStorageReactive.value).filter(
|
||||||
|
(key) => pluginStorageReactive.value[key].align === layout || layout === 'all'
|
||||||
|
)
|
||||||
|
|
||||||
|
pluginNames.sort((a, b) => pluginStorageReactive.value[a].index - pluginStorageReactive.value[b].index)
|
||||||
|
|
||||||
|
return pluginNames
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPluginById = (pluginList, pluginId) => {
|
||||||
|
return pluginList.find((item) => item.id === pluginId)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPluginsByPosition = (position, pluginList) => {
|
||||||
|
return getPluginsByLayout(position).map((pluginId) => getPluginById(pluginList, pluginId))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改某个插件的布局
|
||||||
|
const changePluginLayout = (name, layout) => {
|
||||||
|
if (pluginStorageReactive.value[name]) {
|
||||||
|
pluginStorageReactive.value[name].align = layout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拖拽后改变插件位置
|
||||||
|
* @param {*} from 插件的起始位置
|
||||||
|
* @param {*} to 插件的结束位置
|
||||||
|
* @param {*} oldIndex 插件的起始索引
|
||||||
|
* @param {*} newIndex 插件的结束索引
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取插件显示状态
|
||||||
|
const getPluginShown = (name) => pluginStorageReactive.value[name]?.isShow
|
||||||
|
|
||||||
|
//修改插件显示状态
|
||||||
|
const changePluginShown = (name) => {
|
||||||
|
if (!pluginStorageReactive.value[name]) {
|
||||||
|
pluginStorageReactive.value[name] = { isShow: true }
|
||||||
|
}
|
||||||
|
pluginStorageReactive.value[name].isShow = !pluginStorageReactive.value[name].isShow
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回面板是否宽度可调
|
||||||
|
* @param {string} name 插件名称
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const isPanelWidthResizable = (name) => pluginStorageReactive.value[name]?.widthResizable
|
||||||
|
|
||||||
|
const initPluginStorageReactive = (pluginList) => {
|
||||||
|
if (Object.keys(pluginStorageReactive.value).length) return
|
||||||
|
pluginStorageReactive.value = pluginList
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
isPanelWidthResizable,
|
||||||
|
getFixedPanelsStatus,
|
||||||
|
initPluginStorageReactive,
|
||||||
PLUGIN_NAME,
|
PLUGIN_NAME,
|
||||||
|
PLUGIN_POSITION,
|
||||||
activeSetting,
|
activeSetting,
|
||||||
|
closeSetting,
|
||||||
activePlugin,
|
activePlugin,
|
||||||
closePlugin,
|
closePlugin,
|
||||||
layoutState,
|
layoutState,
|
||||||
getScale,
|
getScale,
|
||||||
setDimension,
|
setDimension,
|
||||||
getDimension,
|
getDimension,
|
||||||
|
getPluginById,
|
||||||
|
pluginState,
|
||||||
getPluginState,
|
getPluginState,
|
||||||
isEmptyPage
|
getSettingState,
|
||||||
|
isEmptyPage,
|
||||||
|
getPluginWidth,
|
||||||
|
changePluginWidth,
|
||||||
|
leftFixedPanelsStorage,
|
||||||
|
rightFixedPanelsStorage,
|
||||||
|
leftMenuShownStorage,
|
||||||
|
rightMenuShownStorage,
|
||||||
|
changeLeftFixedPanels,
|
||||||
|
changeRightFixedPanels,
|
||||||
|
getPluginsByLayout,
|
||||||
|
changePluginLayout,
|
||||||
|
getPluginByLayout,
|
||||||
|
dragPluginLayout,
|
||||||
|
isSameSide,
|
||||||
|
getPluginShown,
|
||||||
|
changePluginShown,
|
||||||
|
changeMenuShown,
|
||||||
|
getMoveDragBarState,
|
||||||
|
changeMoveDragBarState,
|
||||||
|
getPluginsByPosition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@ export default {
|
||||||
id: 'engine.plugins.blockmanage',
|
id: 'engine.plugins.blockmanage',
|
||||||
title: '区块管理',
|
title: '区块管理',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
align: 'top',
|
align: 'leftTop',
|
||||||
icon: 'plugin-icon-symbol'
|
icon: 'plugin-icon-symbol'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
class="plugin-block-setting"
|
class="plugin-block-setting"
|
||||||
title="区块设置"
|
title="区块设置"
|
||||||
|
:align="align"
|
||||||
|
:fixed-name="PLUGIN_NAME.BlockManage"
|
||||||
@mouseleave="onMouseLeave"
|
@mouseleave="onMouseLeave"
|
||||||
@click="handleClick"
|
@click="handleClick"
|
||||||
>
|
>
|
||||||
|
|
@ -86,7 +88,14 @@
|
||||||
<script lang="jsx">
|
<script lang="jsx">
|
||||||
import { reactive, ref, watch, watchEffect, computed } from 'vue'
|
import { reactive, ref, watch, watchEffect, computed } from 'vue'
|
||||||
import { Button as TinyButton, Collapse as TinyCollapse, CollapseItem as TinyCollapseItem } from '@opentiny/vue'
|
import { Button as TinyButton, Collapse as TinyCollapse, CollapseItem as TinyCollapseItem } from '@opentiny/vue'
|
||||||
import { useModal, getMergeMeta, useBlock, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
|
import {
|
||||||
|
useLayout,
|
||||||
|
useModal,
|
||||||
|
getMergeMeta,
|
||||||
|
useBlock,
|
||||||
|
getMetaApi,
|
||||||
|
META_SERVICE
|
||||||
|
} from '@opentiny/tiny-engine-meta-register'
|
||||||
import { BlockHistoryList, PluginSetting, CloseIcon, SvgButton, ButtonGroup } from '@opentiny/tiny-engine-common'
|
import { BlockHistoryList, PluginSetting, CloseIcon, SvgButton, ButtonGroup } from '@opentiny/tiny-engine-common'
|
||||||
import { previewBlock } from '@opentiny/tiny-engine-common/js/preview'
|
import { previewBlock } from '@opentiny/tiny-engine-common/js/preview'
|
||||||
import { LifeCycles } from '@opentiny/tiny-engine-common'
|
import { LifeCycles } from '@opentiny/tiny-engine-common'
|
||||||
|
|
@ -152,6 +161,9 @@ export default {
|
||||||
})
|
})
|
||||||
const blockConfigForm = ref(null)
|
const blockConfigForm = ref(null)
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.BlockManage))
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
activeName: ['base', 'attribute', 'event', 'lifeCycle', 'history'],
|
activeName: ['base', 'attribute', 'event', 'lifeCycle', 'history'],
|
||||||
backupList: [],
|
backupList: [],
|
||||||
|
|
@ -277,6 +289,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
|
PLUGIN_NAME,
|
||||||
state,
|
state,
|
||||||
isOpen,
|
isOpen,
|
||||||
showDeployBlockDialog,
|
showDeployBlockDialog,
|
||||||
|
|
|
||||||
|
|
@ -1,129 +1,128 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="plugin-block">
|
<plugin-panel
|
||||||
<plugin-panel
|
title="区块管理"
|
||||||
class="block-manage"
|
class="plugin-block"
|
||||||
title="区块管理"
|
:fixed-name="PLUGIN_NAME.BlockManage"
|
||||||
:docsUrl="docsUrl"
|
:fixedPanels="fixedPanels"
|
||||||
:isShowDocsIcon="true"
|
:docsUrl="docsUrl"
|
||||||
:isCloseLeft="false"
|
:isShowDocsIcon="true"
|
||||||
@close="closePanel"
|
@close="close"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<svg-button name="add-page" placement="bottom" tips="新建区块" @click="openBlockAdd"></svg-button>
|
<svg-button name="add-page" placement="bottom" tips="新建区块" @click="openBlockAdd"></svg-button>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="app-manage-type">
|
<div class="app-manage-type">
|
||||||
<tiny-select
|
<tiny-select
|
||||||
ref="groupSelect"
|
ref="groupSelect"
|
||||||
v-model="state.categoryId"
|
v-model="state.categoryId"
|
||||||
popper-class="block-popper"
|
popper-class="block-popper"
|
||||||
:placeholder="groupLabels.selectPlaceholder"
|
:placeholder="groupLabels.selectPlaceholder"
|
||||||
filterable
|
filterable
|
||||||
:filter-method="categoryFilter"
|
:filter-method="categoryFilter"
|
||||||
clearable
|
clearable
|
||||||
top-create
|
top-create
|
||||||
@top-create-click="createCategory"
|
@top-create-click="createCategory"
|
||||||
@change="changeCategory"
|
@change="changeCategory"
|
||||||
@clear="changeCategory"
|
@clear="changeCategory"
|
||||||
@visible-change="handleSelectVisibleChange"
|
@visible-change="handleSelectVisibleChange"
|
||||||
class="search-select"
|
class="search-select"
|
||||||
|
>
|
||||||
|
<tiny-option
|
||||||
|
v-for="item in categoryList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
class="block-group-option-item"
|
||||||
>
|
>
|
||||||
<tiny-option
|
<div class="block-item">
|
||||||
v-for="item in categoryList"
|
<span>{{ item.name }}</span>
|
||||||
:key="item.id"
|
<div class="item-btns">
|
||||||
:label="item.name"
|
<svg-button
|
||||||
:value="item.id"
|
class="item-icon"
|
||||||
class="block-group-option-item"
|
name="to-edit"
|
||||||
>
|
:hoverBgColor="false"
|
||||||
<div class="block-item">
|
@click.stop="editCategory(item)"
|
||||||
<span>{{ item.name }}</span>
|
></svg-button>
|
||||||
<div class="item-btns">
|
<tiny-popover
|
||||||
<svg-button
|
:modelValue="state.currentDeleteGroupId === item.id"
|
||||||
class="item-icon"
|
placement="right"
|
||||||
name="to-edit"
|
trigger="manual"
|
||||||
:hoverBgColor="false"
|
popper-class="block-category-option-popper-wrapper"
|
||||||
@click.stop="editCategory(item)"
|
@update:modelValue="handleChangeDeletePopoverVisible"
|
||||||
></svg-button>
|
>
|
||||||
<tiny-popover
|
<div class="popper-confirm" @mousedown.stop="">
|
||||||
:modelValue="state.currentDeleteGroupId === item.id"
|
<div class="popper-confirm-header">删除</div>
|
||||||
placement="right"
|
<div class="popper-confirm-content">
|
||||||
trigger="manual"
|
<span class="title">{{ groupLabels.deletePrompt }}</span>
|
||||||
popper-class="block-category-option-popper-wrapper"
|
|
||||||
@update:modelValue="handleChangeDeletePopoverVisible"
|
|
||||||
>
|
|
||||||
<div class="popper-confirm" @mousedown.stop="">
|
|
||||||
<div class="popper-confirm-header">删除</div>
|
|
||||||
<div class="popper-confirm-content">
|
|
||||||
<span class="title">{{ groupLabels.deletePrompt }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="popper-confirm-footer">
|
|
||||||
<tiny-button class="cancel-btn" size="small" @click="handleShowDeleteModal(null)"
|
|
||||||
>取消</tiny-button
|
|
||||||
>
|
|
||||||
<tiny-button class="confirm-btn" size="small" type="primary" @click="delCategory(item.id)"
|
|
||||||
>确定</tiny-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<template #reference>
|
<div class="popper-confirm-footer">
|
||||||
<svg-button
|
<tiny-button class="cancel-btn" size="small" @click="handleShowDeleteModal(null)"
|
||||||
v-if="!item.blocks.length"
|
>取消</tiny-button
|
||||||
class="item-icon"
|
>
|
||||||
name="delete"
|
<tiny-button class="confirm-btn" size="small" type="primary" @click="delCategory(item.id)"
|
||||||
:hoverBgColor="false"
|
>确定</tiny-button
|
||||||
@click.stop="handleShowDeleteModal(item.id)"
|
>
|
||||||
></svg-button>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</tiny-popover>
|
<template #reference>
|
||||||
</div>
|
<svg-button
|
||||||
|
v-if="!item.blocks.length"
|
||||||
|
class="item-icon"
|
||||||
|
name="delete"
|
||||||
|
:hoverBgColor="false"
|
||||||
|
@click.stop="handleShowDeleteModal(item.id)"
|
||||||
|
></svg-button>
|
||||||
|
</template>
|
||||||
|
</tiny-popover>
|
||||||
</div>
|
</div>
|
||||||
</tiny-option>
|
</div>
|
||||||
</tiny-select>
|
</tiny-option>
|
||||||
</div>
|
</tiny-select>
|
||||||
<div class="app-manage-search">
|
</div>
|
||||||
<tiny-search v-model="state.searchKey" placeholder="搜索">
|
<div class="app-manage-search">
|
||||||
<template #prefix>
|
<tiny-search v-model="state.searchKey" placeholder="搜索">
|
||||||
<tiny-icon-search />
|
<template #prefix>
|
||||||
</template>
|
<tiny-icon-search />
|
||||||
</tiny-search>
|
</template>
|
||||||
</div>
|
</tiny-search>
|
||||||
<div class="plugin-block-list">
|
</div>
|
||||||
<plugin-block-list
|
<div class="plugin-block-list">
|
||||||
:data="state.blockList"
|
<plugin-block-list
|
||||||
:isBlockManage="true"
|
:data="state.blockList"
|
||||||
:showBlockShot="true"
|
:isBlockManage="true"
|
||||||
:blockStyle="state.layout"
|
:showBlockShot="true"
|
||||||
default-icon-tip="查看区块"
|
:blockStyle="state.layout"
|
||||||
:externalBlock="externalBlock"
|
default-icon-tip="查看区块"
|
||||||
@editBlock="editBlock"
|
:externalBlock="externalBlock"
|
||||||
@iconClick="openSettingPanel"
|
@editBlock="editBlock"
|
||||||
></plugin-block-list>
|
@iconClick="openSettingPanel"
|
||||||
</div>
|
></plugin-block-list>
|
||||||
<block-setting></block-setting>
|
</div>
|
||||||
<div class="block-footer">
|
<block-setting></block-setting>
|
||||||
<tiny-dropdown trigger="click" @item-click="changeType">
|
<div class="block-footer">
|
||||||
<span>
|
<tiny-dropdown trigger="click" @item-click="changeType">
|
||||||
<span>{{ state.sortTypeLabel }}</span>
|
<span>
|
||||||
</span>
|
<span>{{ state.sortTypeLabel }}</span>
|
||||||
<template #dropdown>
|
</span>
|
||||||
<tiny-dropdown-menu
|
<template #dropdown>
|
||||||
popper-class="my-class"
|
<tiny-dropdown-menu
|
||||||
placement="top"
|
popper-class="my-class"
|
||||||
:options="state.sortOptions"
|
placement="top"
|
||||||
></tiny-dropdown-menu>
|
:options="state.sortOptions"
|
||||||
</template>
|
></tiny-dropdown-menu>
|
||||||
</tiny-dropdown>
|
</template>
|
||||||
<block-group-arrange v-model="state.layout" :arrangeList="state.arrangeList"></block-group-arrange>
|
</tiny-dropdown>
|
||||||
</div>
|
<block-group-arrange v-model="state.layout" :arrangeList="state.arrangeList"></block-group-arrange>
|
||||||
</template>
|
</div>
|
||||||
</plugin-panel>
|
</template>
|
||||||
<category-edit v-model="state.editVisible" :initialValue="state.groupInitialValue"></category-edit>
|
</plugin-panel>
|
||||||
<save-new-block :boxVisibility="boxVisibility" @close="close"></save-new-block>
|
<category-edit v-model="state.editVisible" :initialValue="state.groupInitialValue"></category-edit>
|
||||||
</div>
|
<save-new-block :boxVisibility="boxVisibility" @close="close"></save-new-block>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="jsx">
|
<script lang="jsx">
|
||||||
import { ref, reactive, computed, watch } from 'vue'
|
import { ref, reactive, computed, watch, provide } from 'vue'
|
||||||
import {
|
import {
|
||||||
Search as TinySearch,
|
Search as TinySearch,
|
||||||
Select as TinySelect,
|
Select as TinySelect,
|
||||||
|
|
@ -217,8 +216,13 @@ export default {
|
||||||
TinyButton,
|
TinyButton,
|
||||||
TinyIconSearch: IconSearch()
|
TinyIconSearch: IconSearch()
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
setup() {
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['close'],
|
||||||
|
setup(props, { emit }) {
|
||||||
const docsUrl = useHelp().getDocsUrl('block')
|
const docsUrl = useHelp().getDocsUrl('block')
|
||||||
const { getBlockList, sort } = useBlock()
|
const { getBlockList, sort } = useBlock()
|
||||||
const { isSaved } = useCanvas()
|
const { isSaved } = useCanvas()
|
||||||
|
|
@ -266,6 +270,14 @@ export default {
|
||||||
|
|
||||||
const groupSelect = ref(null)
|
const groupSelect = ref(null)
|
||||||
|
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [getBlockList(), state.searchKey, state.publishFilterType],
|
() => [getBlockList(), state.searchKey, state.publishFilterType],
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -304,15 +316,15 @@ export default {
|
||||||
}
|
}
|
||||||
const close = () => {
|
const close = () => {
|
||||||
boxVisibility.value = false
|
boxVisibility.value = false
|
||||||
|
emit('close')
|
||||||
|
closePanel()
|
||||||
}
|
}
|
||||||
|
|
||||||
const editBlock = async (block) => {
|
const editBlock = async (block) => {
|
||||||
const isEdit = true
|
const isEdit = true
|
||||||
|
|
||||||
if (isSaved()) {
|
if (isSaved()) {
|
||||||
await refreshBlockData(block)
|
await refreshBlockData(block)
|
||||||
useBlock().initBlock(block, {}, isEdit)
|
|
||||||
useLayout().closePlugin()
|
|
||||||
closePanel()
|
|
||||||
getMetaApi(META_SERVICE.GlobalService).updateBlockId(block.id)
|
getMetaApi(META_SERVICE.GlobalService).updateBlockId(block.id)
|
||||||
} else {
|
} else {
|
||||||
confirm({
|
confirm({
|
||||||
|
|
@ -320,8 +332,6 @@ export default {
|
||||||
exec: async () => {
|
exec: async () => {
|
||||||
await refreshBlockData(block)
|
await refreshBlockData(block)
|
||||||
useBlock().initBlock(block, {}, isEdit)
|
useBlock().initBlock(block, {}, isEdit)
|
||||||
useLayout().closePlugin()
|
|
||||||
closePanel()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -423,6 +433,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
state,
|
state,
|
||||||
groupSelect,
|
groupSelect,
|
||||||
categoryList,
|
categoryList,
|
||||||
|
|
@ -458,7 +469,7 @@ export default {
|
||||||
}
|
}
|
||||||
.app-manage-type {
|
.app-manage-type {
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
margin: 12px 0;
|
margin-bottom: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
.search-select {
|
.search-select {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@ export default {
|
||||||
id: 'engine.plugins.bridge',
|
id: 'engine.plugins.bridge',
|
||||||
title: '资源管理',
|
title: '资源管理',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
align: 'top',
|
align: 'leftTop',
|
||||||
icon: 'plugin-icon-sresources'
|
icon: 'plugin-icon-sresources'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-setting v-if="isOpen">
|
<plugin-setting v-if="isOpen" :align="align" :fixed-name="PLUGIN_NAME.Bridge">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="title-wrap">
|
<div class="title-wrap">
|
||||||
<span>{{ state.title }}</span>
|
<span>{{ state.title }}</span>
|
||||||
|
|
@ -112,7 +112,7 @@ import {
|
||||||
getResourceNamesByType
|
getResourceNamesByType
|
||||||
} from './js/resource'
|
} from './js/resource'
|
||||||
import { VueMonaco as MonacoEditor, PluginSetting, SvgButton, ButtonGroup } from '@opentiny/tiny-engine-common'
|
import { VueMonaco as MonacoEditor, PluginSetting, SvgButton, ButtonGroup } from '@opentiny/tiny-engine-common'
|
||||||
import { useModal, useNotify, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
|
import { useLayout, useModal, useNotify, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { getMergeMeta } from '@opentiny/tiny-engine-meta-register'
|
import { getMergeMeta } from '@opentiny/tiny-engine-meta-register'
|
||||||
|
|
||||||
const isOpen = ref(false)
|
const isOpen = ref(false)
|
||||||
|
|
@ -151,6 +151,9 @@ export default {
|
||||||
}
|
}
|
||||||
const { confirm } = useModal()
|
const { confirm } = useModal()
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.Bridge))
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
resource: computed(() => getResource()),
|
resource: computed(() => getResource()),
|
||||||
name: '',
|
name: '',
|
||||||
|
|
@ -273,6 +276,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
|
PLUGIN_NAME,
|
||||||
rules,
|
rules,
|
||||||
resourceForm,
|
resourceForm,
|
||||||
editor,
|
editor,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-panel title="资源管理" class="plugin-bridge" :isCloseLeft="false" @close="closePanel">
|
<plugin-panel
|
||||||
|
title="资源管理"
|
||||||
|
class="plugin-bridge"
|
||||||
|
:fixed-name="PLUGIN_NAME.Bridge"
|
||||||
|
:fixedPanels="fixedPanels"
|
||||||
|
@close="closePanel"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<svg-button name="add-utils" placement="left" :tips="tips" @click="addResource('npm')"></svg-button>
|
<svg-button name="add-utils" placement="left" :tips="tips" @click="addResource('npm')"></svg-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -11,8 +17,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, computed } from 'vue'
|
import { ref, reactive, computed, provide } from 'vue'
|
||||||
import { PluginPanel, SvgButton } from '@opentiny/tiny-engine-common'
|
import { PluginPanel, SvgButton } from '@opentiny/tiny-engine-common'
|
||||||
|
import { useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { RESOURCE_TYPE } from './js/resource'
|
import { RESOURCE_TYPE } from './js/resource'
|
||||||
import BridgeManage from './BridgeManage.vue'
|
import BridgeManage from './BridgeManage.vue'
|
||||||
import BridgeSetting, { openPanel, closePanel } from './BridgeSetting.vue'
|
import BridgeSetting, { openPanel, closePanel } from './BridgeSetting.vue'
|
||||||
|
|
@ -25,11 +32,23 @@ export default {
|
||||||
BridgeManage,
|
BridgeManage,
|
||||||
BridgeSetting
|
BridgeSetting
|
||||||
},
|
},
|
||||||
setup() {
|
props: {
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
const activedName = ref(RESOURCE_TYPE.Util)
|
const activedName = ref(RESOURCE_TYPE.Util)
|
||||||
const utilsRef = ref(null)
|
const utilsRef = ref(null)
|
||||||
const tips = computed(() => RESOURCE_TIP[activedName.value])
|
const tips = computed(() => RESOURCE_TIP[activedName.value])
|
||||||
|
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const openBridgePanel = () => {
|
const openBridgePanel = () => {
|
||||||
openPanel()
|
openPanel()
|
||||||
}
|
}
|
||||||
|
|
@ -43,6 +62,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
addResource,
|
addResource,
|
||||||
RESOURCE_TYPE,
|
RESOURCE_TYPE,
|
||||||
activedName,
|
activedName,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@ export default {
|
||||||
id: 'engine.plugins.collections',
|
id: 'engine.plugins.collections',
|
||||||
title: '数据源',
|
title: '数据源',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
align: 'top',
|
align: 'leftTop',
|
||||||
icon: 'plugin-icon-data'
|
icon: 'plugin-icon-data'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-setting v-if="isOpen" title="设置数据源" class="data-source-form">
|
<plugin-setting
|
||||||
|
v-if="isOpen"
|
||||||
|
title="设置数据源"
|
||||||
|
class="data-source-form plugin-datasource"
|
||||||
|
:fixed-name="PLUGIN_NAME.Collections"
|
||||||
|
:align="align"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<button-group>
|
<button-group>
|
||||||
<tiny-button class="field-save" type="primary" @click="save">保存</tiny-button>
|
<tiny-button class="field-save" type="primary" @click="save">保存</tiny-button>
|
||||||
|
|
@ -27,7 +33,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="jsx">
|
<script lang="jsx">
|
||||||
import { reactive, ref, watch } from 'vue'
|
import { reactive, ref, watch, computed } from 'vue'
|
||||||
import { Form, Button } from '@opentiny/vue'
|
import { Form, Button } from '@opentiny/vue'
|
||||||
import { ButtonGroup, PluginSetting, SvgButton } from '@opentiny/tiny-engine-common'
|
import { ButtonGroup, PluginSetting, SvgButton } from '@opentiny/tiny-engine-common'
|
||||||
import DataSourceType from './DataSourceType.vue'
|
import DataSourceType from './DataSourceType.vue'
|
||||||
|
|
@ -41,7 +47,14 @@ import {
|
||||||
requestDeleteDataSource,
|
requestDeleteDataSource,
|
||||||
requestGenerateDataSource
|
requestGenerateDataSource
|
||||||
} from './js/http'
|
} from './js/http'
|
||||||
import { useModal, useDataSource, useNotify, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
|
import {
|
||||||
|
useLayout,
|
||||||
|
useModal,
|
||||||
|
useDataSource,
|
||||||
|
useNotify,
|
||||||
|
getMetaApi,
|
||||||
|
META_SERVICE
|
||||||
|
} from '@opentiny/tiny-engine-meta-register'
|
||||||
import { extend } from '@opentiny/vue-renderless/common/object'
|
import { extend } from '@opentiny/vue-renderless/common/object'
|
||||||
|
|
||||||
const isOpen = ref(false)
|
const isOpen = ref(false)
|
||||||
|
|
@ -84,6 +97,9 @@ export default {
|
||||||
dataSource: {}
|
dataSource: {}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.Collections))
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => state.dataSource.name,
|
() => state.dataSource.name,
|
||||||
(value) => {
|
(value) => {
|
||||||
|
|
@ -131,7 +147,8 @@ export default {
|
||||||
|
|
||||||
dataSourceState.dataSourceColumn = { name, type: type || 'array', columns: filterColumns }
|
dataSourceState.dataSourceColumn = { name, type: type || 'array', columns: filterColumns }
|
||||||
dataSourceState.dataSourceColumnCopies = extend(true, {}, dataSourceState.dataSourceColumn)
|
dataSourceState.dataSourceColumnCopies = extend(true, {}, dataSourceState.dataSourceColumn)
|
||||||
}
|
},
|
||||||
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
const closeAllPanel = () => {
|
const closeAllPanel = () => {
|
||||||
|
|
@ -240,6 +257,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
|
PLUGIN_NAME,
|
||||||
state,
|
state,
|
||||||
isOpen,
|
isOpen,
|
||||||
save,
|
save,
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="isOpen" class="global-data-handler">
|
<plugin-setting
|
||||||
<plugin-setting title="全局设置" @cancel="close" @save="saveGlobalDataHandle">
|
v-if="isOpen"
|
||||||
<template #content>
|
title="全局设置"
|
||||||
<tiny-collapse v-model="activeNames">
|
class="plugin-datasource global-data-handler"
|
||||||
<tiny-collapse-item title="请求参数处理函数(willFetch)" name="willFetch">
|
:align="align"
|
||||||
<data-handler-editor v-model="state.willFetchValue"></data-handler-editor>
|
:fixed-name="PLUGIN_NAME.Collections"
|
||||||
</tiny-collapse-item>
|
@cancel="close"
|
||||||
<tiny-collapse-item title="请求完成回调函数(dataHandler)" name="dataHandler">
|
@save="saveGlobalDataHandle"
|
||||||
<data-handler-editor v-model="state.dataHandlerValue"></data-handler-editor>
|
>
|
||||||
</tiny-collapse-item>
|
<template #content>
|
||||||
<tiny-collapse-item title="请求失败后的回调函数(errorHandler)" name="errorHandler">
|
<tiny-collapse v-model="activeNames">
|
||||||
<data-handler-editor v-model="state.errorHandlerValue"></data-handler-editor>
|
<tiny-collapse-item title="请求参数处理函数(willFetch)" name="willFetch">
|
||||||
</tiny-collapse-item>
|
<data-handler-editor v-model="state.willFetchValue"></data-handler-editor>
|
||||||
</tiny-collapse>
|
</tiny-collapse-item>
|
||||||
</template>
|
<tiny-collapse-item title="请求完成回调函数(dataHandler)" name="dataHandler">
|
||||||
</plugin-setting>
|
<data-handler-editor v-model="state.dataHandlerValue"></data-handler-editor>
|
||||||
</div>
|
</tiny-collapse-item>
|
||||||
|
<tiny-collapse-item title="请求失败后的回调函数(errorHandler)" name="errorHandler">
|
||||||
|
<data-handler-editor v-model="state.errorHandlerValue"></data-handler-editor>
|
||||||
|
</tiny-collapse-item>
|
||||||
|
</tiny-collapse>
|
||||||
|
</template>
|
||||||
|
</plugin-setting>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DataHandlerEditor from './RemoteDataAdapterForm.vue'
|
import DataHandlerEditor from './RemoteDataAdapterForm.vue'
|
||||||
import { watch, ref, nextTick, reactive } from 'vue'
|
import { watch, ref, nextTick, reactive, computed } from 'vue'
|
||||||
import { requestGlobalDataHandler } from './js/http'
|
import { requestGlobalDataHandler } from './js/http'
|
||||||
import { useModal, useResource, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
|
import { useLayout, useModal, useResource, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { PluginSetting } from '@opentiny/tiny-engine-common'
|
import { PluginSetting } from '@opentiny/tiny-engine-common'
|
||||||
import { Collapse, CollapseItem } from '@opentiny/vue'
|
import { Collapse, CollapseItem } from '@opentiny/vue'
|
||||||
import { constants } from '@opentiny/tiny-engine-utils'
|
import { constants } from '@opentiny/tiny-engine-utils'
|
||||||
|
|
@ -48,6 +54,9 @@ export default {
|
||||||
setup() {
|
setup() {
|
||||||
const { confirm } = useModal()
|
const { confirm } = useModal()
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.Collections))
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
dataHandlerValue: useResource().appSchemaState?.dataHandler?.value,
|
dataHandlerValue: useResource().appSchemaState?.dataHandler?.value,
|
||||||
willFetchValue: useResource().appSchemaState.willFetch?.value,
|
willFetchValue: useResource().appSchemaState.willFetch?.value,
|
||||||
|
|
@ -88,6 +97,8 @@ export default {
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
|
PLUGIN_NAME,
|
||||||
isOpen,
|
isOpen,
|
||||||
close,
|
close,
|
||||||
saveGlobalDataHandle,
|
saveGlobalDataHandle,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
:is-icon-button="false"
|
:is-icon-button="false"
|
||||||
:showIfFullScreen="true"
|
:showIfFullScreen="true"
|
||||||
|
:fixed-name="PLUGIN_NAME.Collections"
|
||||||
|
:align="align"
|
||||||
title="静态数据管理"
|
title="静态数据管理"
|
||||||
class="datasource-record-list"
|
class="datasource-record-list"
|
||||||
@cancel="closeRecordList"
|
@cancel="closeRecordList"
|
||||||
|
|
@ -122,7 +124,8 @@ export default {
|
||||||
const grid = ref(null)
|
const grid = ref(null)
|
||||||
const { confirm } = useModal()
|
const { confirm } = useModal()
|
||||||
const { toClipboard } = useClipboard()
|
const { toClipboard } = useClipboard()
|
||||||
const { layoutState } = useLayout()
|
const { layoutState, PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.Collections))
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
totalData: [],
|
totalData: [],
|
||||||
|
|
@ -559,6 +562,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
|
PLUGIN_NAME,
|
||||||
isOpen,
|
isOpen,
|
||||||
state,
|
state,
|
||||||
grid,
|
grid,
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
<div class="remote">
|
<div class="remote">
|
||||||
<plugin-setting
|
<plugin-setting
|
||||||
title="获取远程字段"
|
title="获取远程字段"
|
||||||
class="remote-setting"
|
class="remote-setting plugin-datasource"
|
||||||
:isSecond="true"
|
:isSecond="true"
|
||||||
|
:align="align"
|
||||||
@cancel="closePanel"
|
@cancel="closePanel"
|
||||||
@save="saveRemote"
|
@save="saveRemote"
|
||||||
>
|
>
|
||||||
|
|
@ -52,7 +53,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reactive, watch, ref } from 'vue'
|
import { reactive, watch, ref, computed } from 'vue'
|
||||||
import { Collapse, CollapseItem, Tabs, TabItem, Button } from '@opentiny/vue'
|
import { Collapse, CollapseItem, Tabs, TabItem, Button } from '@opentiny/vue'
|
||||||
import { PluginSetting } from '@opentiny/tiny-engine-common'
|
import { PluginSetting } from '@opentiny/tiny-engine-common'
|
||||||
import DataSourceRemoteForm, { getServiceForm } from './DataSourceRemoteForm.vue'
|
import DataSourceRemoteForm, { getServiceForm } from './DataSourceRemoteForm.vue'
|
||||||
|
|
@ -61,7 +62,7 @@ import DataSourceRemoteAutoload from './DataSourceRemoteAutoload.vue'
|
||||||
import DataSourceRemoteAdapter from './DataSourceRemoteDataAdapter.vue'
|
import DataSourceRemoteAdapter from './DataSourceRemoteDataAdapter.vue'
|
||||||
import DataSrouceRemoteDataResult, { getResponseData } from './DataSourceRemoteDataResult.vue'
|
import DataSrouceRemoteDataResult, { getResponseData } from './DataSourceRemoteDataResult.vue'
|
||||||
import { open as openRemoteMapping } from './DataSourceRemoteMapping.vue'
|
import { open as openRemoteMapping } from './DataSourceRemoteMapping.vue'
|
||||||
import { useDataSource, useNotify } from '@opentiny/tiny-engine-meta-register'
|
import { useLayout, useDataSource, useNotify } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { isEmptyObject } from '@opentiny/vue-renderless/common/type'
|
import { isEmptyObject } from '@opentiny/vue-renderless/common/type'
|
||||||
import { utils } from '@opentiny/tiny-engine-utils'
|
import { utils } from '@opentiny/tiny-engine-utils'
|
||||||
import { getRequest } from './js/datasource'
|
import { getRequest } from './js/datasource'
|
||||||
|
|
@ -114,6 +115,9 @@ export default {
|
||||||
const dataSourceRemoteAdapteRef = ref(null)
|
const dataSourceRemoteAdapteRef = ref(null)
|
||||||
const { dataSourceState } = useDataSource()
|
const { dataSourceState } = useDataSource()
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.Collections))
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
remoteData: { options: {} },
|
remoteData: { options: {} },
|
||||||
activeName: ['excute', 'result'],
|
activeName: ['excute', 'result'],
|
||||||
|
|
@ -221,6 +225,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
state,
|
state,
|
||||||
dataSourceRemoteAdapteRef,
|
dataSourceRemoteAdapteRef,
|
||||||
closePanel: close,
|
closePanel: close,
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,67 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="plugin-datasource">
|
<plugin-panel
|
||||||
<plugin-panel title="数据源">
|
title="数据源"
|
||||||
<template #header>
|
class="plugin-datasource"
|
||||||
<link-button :href="docsUrl"></link-button>
|
:fixed-name="PLUGIN_NAME.Collections"
|
||||||
<svg-button
|
:fixedPanels="fixedPanels"
|
||||||
class="set-data-source"
|
:docsUrl="docsUrl"
|
||||||
tips="全局设置"
|
:isShowDocsIcon="true"
|
||||||
name="global-setting"
|
@close="$emit('close')"
|
||||||
@click="openGlobalDataHanderPanel"
|
>
|
||||||
></svg-button>
|
<template #header>
|
||||||
<svg-button
|
<svg-button
|
||||||
class="refresh-data-source"
|
class="set-data-source"
|
||||||
tips="刷新数据源"
|
tips="全局设置"
|
||||||
name="flow-refresh"
|
name="global-setting"
|
||||||
@click="refreshDataSource"
|
@click="openGlobalDataHanderPanel"
|
||||||
></svg-button>
|
></svg-button>
|
||||||
</template>
|
<svg-button
|
||||||
<template #content>
|
class="refresh-data-source"
|
||||||
<tiny-button class="add-data-source" @click="openDataSourceFormPanel()">
|
tips="刷新数据源"
|
||||||
<svg-icon name="add"></svg-icon>添加数据源
|
name="flow-refresh"
|
||||||
</tiny-button>
|
@click="refreshDataSource"
|
||||||
<data-source-list @edit="openDataSourceFormPanel"></data-source-list>
|
></svg-button>
|
||||||
</template>
|
</template>
|
||||||
</plugin-panel>
|
<template #content>
|
||||||
<data-source-remote-panel
|
<tiny-button class="add-data-source" @click="openDataSourceFormPanel()">
|
||||||
v-if="isOpenRemotePanel"
|
<svg-icon name="add"></svg-icon>添加数据源
|
||||||
v-model="state.currentDataSource.data"
|
</tiny-button>
|
||||||
:editable="state.editable"
|
<data-source-list @edit="openDataSourceFormPanel"></data-source-list>
|
||||||
@confirm="getRomoteReponseData"
|
</template>
|
||||||
></data-source-remote-panel>
|
</plugin-panel>
|
||||||
<data-source-form
|
<data-source-remote-panel
|
||||||
v-model="state.currentDataSource"
|
v-if="isOpenRemotePanel"
|
||||||
:editable="state.editable"
|
v-model="state.currentDataSource.data"
|
||||||
@save="refreshDataSource"
|
:editable="state.editable"
|
||||||
></data-source-form>
|
@confirm="getRomoteReponseData"
|
||||||
<data-source-remote-mapping
|
></data-source-remote-panel>
|
||||||
v-if="isOpenSourceRemoteMapping"
|
<data-source-form
|
||||||
v-model="state.remoteFields"
|
v-model="state.currentDataSource"
|
||||||
:data="state.remoteResponData"
|
:editable="state.editable"
|
||||||
></data-source-remote-mapping>
|
@save="refreshDataSource"
|
||||||
<data-source-global-data-handler></data-source-global-data-handler>
|
></data-source-form>
|
||||||
</div>
|
<data-source-remote-mapping
|
||||||
|
v-if="isOpenSourceRemoteMapping"
|
||||||
|
v-model="state.remoteFields"
|
||||||
|
:data="state.remoteResponData"
|
||||||
|
></data-source-remote-mapping>
|
||||||
|
<data-source-global-data-handler></data-source-global-data-handler>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reactive, watch } from 'vue'
|
import { reactive, watch, provide } from 'vue'
|
||||||
import { Button } from '@opentiny/vue'
|
import { Button } from '@opentiny/vue'
|
||||||
import DataSourceList, { refresh as refreshDataSourceList, clearActive } from './DataSourceList.vue'
|
import DataSourceList, { refresh as refreshDataSourceList, clearActive } from './DataSourceList.vue'
|
||||||
import DataSourceRemotePanel, {
|
import DataSourceRemotePanel, {
|
||||||
close as closeRemotePanel,
|
close as closeRemotePanel,
|
||||||
isOpen as isOpenRemotePanel
|
isOpen as isOpenRemotePanel
|
||||||
} from './DataSourceRemotePanel.vue'
|
} from './DataSourceRemotePanel.vue'
|
||||||
import { PluginPanel, SvgButton, LinkButton } from '@opentiny/tiny-engine-common'
|
import { PluginPanel, SvgButton } from '@opentiny/tiny-engine-common'
|
||||||
import DataSourceForm, { open as openDataSourceForm, close as closeDataSourceForm } from './DataSourceForm.vue'
|
import DataSourceForm, { open as openDataSourceForm, close as closeDataSourceForm } from './DataSourceForm.vue'
|
||||||
import { close as closeRecordList } from './DataSourceRecordList.vue'
|
import { close as closeRecordList } from './DataSourceRecordList.vue'
|
||||||
import { close as closeRecordForm } from './DataSourceRecordForm.vue'
|
import { close as closeRecordForm } from './DataSourceRecordForm.vue'
|
||||||
import DataSourceRemoteMapping, { isOpen as isOpenSourceRemoteMapping } from './DataSourceRemoteMapping.vue'
|
import DataSourceRemoteMapping, { isOpen as isOpenSourceRemoteMapping } from './DataSourceRemoteMapping.vue'
|
||||||
import { useDataSource, useHelp } from '@opentiny/tiny-engine-meta-register'
|
import { useDataSource, useHelp, useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { requestUpdateDataSource } from './js/http'
|
import { requestUpdateDataSource } from './js/http'
|
||||||
import DataSourceGlobalDataHandler, {
|
import DataSourceGlobalDataHandler, {
|
||||||
open as openGlobalDataHander,
|
open as openGlobalDataHander,
|
||||||
|
|
@ -72,10 +77,14 @@ export default {
|
||||||
DataSourceGlobalDataHandler,
|
DataSourceGlobalDataHandler,
|
||||||
PluginPanel,
|
PluginPanel,
|
||||||
DataSourceForm,
|
DataSourceForm,
|
||||||
SvgButton,
|
SvgButton
|
||||||
LinkButton
|
|
||||||
},
|
},
|
||||||
setup() {
|
props: {
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
const docsUrl = useHelp().getDocsUrl('datasource')
|
const docsUrl = useHelp().getDocsUrl('datasource')
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
editable: true,
|
editable: true,
|
||||||
|
|
@ -84,6 +93,14 @@ export default {
|
||||||
remoteResponData: {}
|
remoteResponData: {}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const { dataSourceState, saveDataSource } = useDataSource()
|
const { dataSourceState, saveDataSource } = useDataSource()
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
@ -134,6 +151,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
state,
|
state,
|
||||||
open,
|
open,
|
||||||
isOpenRemotePanel,
|
isOpenRemotePanel,
|
||||||
|
|
@ -153,6 +171,7 @@ export default {
|
||||||
}
|
}
|
||||||
.add-data-source {
|
.add-data-source {
|
||||||
margin: 0 12px 12px 12px;
|
margin: 0 12px 12px 12px;
|
||||||
|
width: calc(100% - 24px);
|
||||||
}
|
}
|
||||||
:deep(.help-box) {
|
:deep(.help-box) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ import HelpIcon from './src/HelpIcon.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
id: 'engine.plugins.editorhelp',
|
id: 'engine.plugins.editorhelp',
|
||||||
title: '',
|
title: '帮助',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
icon: HelpIcon,
|
icon: HelpIcon,
|
||||||
align: 'bottom'
|
align: 'leftBottom'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ export default {
|
||||||
{
|
{
|
||||||
title: '组件设置',
|
title: '组件设置',
|
||||||
text: '拖拽至画布中的组件或区块,在这里进行属性、样式、事件绑定等众多高级配置;',
|
text: '拖拽至画布中的组件或区块,在这里进行属性、样式、事件绑定等众多高级配置;',
|
||||||
domElement: '#tiny-right-panel',
|
domElement: '#rightTop',
|
||||||
classes: 'lwocode-guide-toolbar-right',
|
classes: 'lwocode-guide-toolbar-right',
|
||||||
popPosition: 'left',
|
popPosition: 'left',
|
||||||
button: [
|
button: [
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ export default {
|
||||||
id: 'engine.plugins.i18n',
|
id: 'engine.plugins.i18n',
|
||||||
title: '国际化',
|
title: '国际化',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
align: 'top',
|
align: 'leftTop',
|
||||||
|
width: 600,
|
||||||
icon: 'plugin-icon-i18n'
|
icon: 'plugin-icon-i18n'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-panel title="国际化资源" :docsUrl="docsUrl" :isShowDocsIcon="true" :isCloseLeft="false" class="plugin-i18n">
|
<plugin-panel
|
||||||
|
title="国际化资源"
|
||||||
|
class="plugin-i18n"
|
||||||
|
:fixed-name="PLUGIN_NAME.I18n"
|
||||||
|
:fixedPanels="fixedPanels"
|
||||||
|
:docsUrl="docsUrl"
|
||||||
|
:isShowDocsIcon="true"
|
||||||
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="language-search-box">
|
<div class="language-search-box">
|
||||||
<tiny-select v-model="currentSearchType" :options="i18nSearchTypes"></tiny-select>
|
<tiny-select v-model="currentSearchType" :options="i18nSearchTypes"></tiny-select>
|
||||||
|
|
@ -113,12 +120,19 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="jsx">
|
<script lang="jsx">
|
||||||
import { computed, ref, watchEffect, reactive, onMounted, nextTick, resolveComponent, watch } from 'vue'
|
import { computed, ref, watchEffect, reactive, onMounted, nextTick, resolveComponent, watch, provide } from 'vue'
|
||||||
import useClipboard from 'vue-clipboard3'
|
import useClipboard from 'vue-clipboard3'
|
||||||
import { Grid, GridColumn, Input, Popover, Button, FileUpload, Loading, Tooltip, Select } from '@opentiny/vue'
|
import { Grid, GridColumn, Input, Popover, Button, FileUpload, Loading, Tooltip, Select } from '@opentiny/vue'
|
||||||
import { iconLoadingShadow, iconUpload } from '@opentiny/vue-icon'
|
import { iconLoadingShadow, iconUpload } from '@opentiny/vue-icon'
|
||||||
import { PluginPanel, SearchEmpty } from '@opentiny/tiny-engine-common'
|
import { PluginPanel, SearchEmpty } from '@opentiny/tiny-engine-common'
|
||||||
import { useTranslate, useModal, useHelp, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
|
import {
|
||||||
|
useTranslate,
|
||||||
|
useModal,
|
||||||
|
useHelp,
|
||||||
|
getMetaApi,
|
||||||
|
META_SERVICE,
|
||||||
|
useLayout
|
||||||
|
} from '@opentiny/tiny-engine-meta-register'
|
||||||
import { getMergeMeta } from '@opentiny/tiny-engine-meta-register'
|
import { getMergeMeta } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { utils, constants } from '@opentiny/tiny-engine-utils'
|
import { utils, constants } from '@opentiny/tiny-engine-utils'
|
||||||
import { BASE_URL } from '@opentiny/tiny-engine-common/js/environments'
|
import { BASE_URL } from '@opentiny/tiny-engine-common/js/environments'
|
||||||
|
|
@ -138,7 +152,12 @@ export default {
|
||||||
SearchEmpty,
|
SearchEmpty,
|
||||||
IconUpload: iconUpload()
|
IconUpload: iconUpload()
|
||||||
},
|
},
|
||||||
setup() {
|
props: {
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
// 组件库iconLoadingShadow图标不能切换颜色,因此不同主题用不同icon
|
// 组件库iconLoadingShadow图标不能切换颜色,因此不同主题用不同icon
|
||||||
const SvgIcon = resolveComponent('SvgIcon')
|
const SvgIcon = resolveComponent('SvgIcon')
|
||||||
const lightSpinnerIcon = iconLoadingShadow()
|
const lightSpinnerIcon = iconLoadingShadow()
|
||||||
|
|
@ -146,6 +165,13 @@ export default {
|
||||||
const isLightTheme = getMergeMeta('engine.config').theme === 'light'
|
const isLightTheme = getMergeMeta('engine.config').theme === 'light'
|
||||||
const { getLangs, i18nResource, currentLanguage, getI18nData } = useTranslate()
|
const { getLangs, i18nResource, currentLanguage, getI18nData } = useTranslate()
|
||||||
const { toClipboard } = useClipboard()
|
const { toClipboard } = useClipboard()
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const fullLangList = computed(() => {
|
const fullLangList = computed(() => {
|
||||||
const langs = getLangs()
|
const langs = getLangs()
|
||||||
|
|
||||||
|
|
@ -392,6 +418,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
sortTypeChanges,
|
sortTypeChanges,
|
||||||
currentSearchType,
|
currentSearchType,
|
||||||
i18nSearchTypes,
|
i18nSearchTypes,
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ export default {
|
||||||
title: '物料',
|
title: '物料',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
icon: 'plugin-icon-materials',
|
icon: 'plugin-icon-materials',
|
||||||
align: 'top'
|
align: 'leftTop'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-setting v-if="panel.show" :title="validGroup.groupName" @cancel="closeGroupPanel" @save="addBlocks">
|
<plugin-setting
|
||||||
|
v-if="panel.show"
|
||||||
|
:align="align"
|
||||||
|
:title="validGroup.groupName"
|
||||||
|
:fixed-name="PLUGIN_NAME.Materials"
|
||||||
|
@cancel="closeGroupPanel"
|
||||||
|
@save="addBlocks"
|
||||||
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="block-add-content">
|
<div class="block-add-content">
|
||||||
<div class="block-add-content-title">区块列表</div>
|
<div class="block-add-content-title">区块列表</div>
|
||||||
|
|
@ -27,12 +34,13 @@
|
||||||
</plugin-setting>
|
</plugin-setting>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { reactive, watch, provide, inject, ref } from 'vue'
|
import { reactive, watch, provide, inject, ref, computed } from 'vue'
|
||||||
import { Search } from '@opentiny/vue'
|
import { Search } from '@opentiny/vue'
|
||||||
import { iconSearch } from '@opentiny/vue-icon'
|
import { iconSearch } from '@opentiny/vue-icon'
|
||||||
import { PluginSetting } from '@opentiny/tiny-engine-common'
|
import { PluginSetting } from '@opentiny/tiny-engine-common'
|
||||||
import {
|
import {
|
||||||
useBlock,
|
useBlock,
|
||||||
|
useLayout,
|
||||||
useModal,
|
useModal,
|
||||||
useResource,
|
useResource,
|
||||||
useNotify,
|
useNotify,
|
||||||
|
|
@ -117,6 +125,9 @@ export default {
|
||||||
|
|
||||||
const validGroup = ref({ ...selectedGroup.value })
|
const validGroup = ref({ ...selectedGroup.value })
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.Materials))
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => selectedGroup.value.groupId,
|
() => selectedGroup.value.groupId,
|
||||||
(groupId) => {
|
(groupId) => {
|
||||||
|
|
@ -271,12 +282,14 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
validGroup,
|
validGroup,
|
||||||
state,
|
state,
|
||||||
panel,
|
panel,
|
||||||
closeGroupPanel,
|
closeGroupPanel,
|
||||||
addBlocks,
|
addBlocks,
|
||||||
searchBlocks
|
searchBlocks,
|
||||||
|
PLUGIN_NAME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-panel :title="shortcut ? '' : title" @close="$emit('close')">
|
<plugin-panel
|
||||||
<template #header>
|
:title="shortcut ? '' : title"
|
||||||
<component
|
:fixed-name="PLUGIN_NAME.Materials"
|
||||||
v-if="!onlyShowDefault"
|
:fixedPanels="fixedPanels"
|
||||||
:is="registryData?.components?.header"
|
@close="$emit('close')"
|
||||||
:fixedPanels="fixedPanels"
|
>
|
||||||
@fix-panel="(id) => $emit('fix-panel', id)"
|
|
||||||
></component>
|
|
||||||
</template>
|
|
||||||
<template #content>
|
<template #content>
|
||||||
<tiny-tabs v-model="activeName" tab-style="button-card" class="full-width-tabs" v-if="!onlyShowDefault">
|
<tiny-tabs v-model="activeName" tab-style="button-card" class="full-width-tabs" v-if="!onlyShowDefault">
|
||||||
<tiny-tab-item :key="item.id" v-for="item in tabComponents" :title="item.title" :name="item.id">
|
<tiny-tab-item :key="item.id" v-for="item in tabComponents" :title="item.title" :name="item.id">
|
||||||
|
|
@ -23,7 +20,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { reactive, provide, ref, computed } from 'vue'
|
import { reactive, provide, ref, computed } from 'vue'
|
||||||
import { Tabs, TabItem } from '@opentiny/vue'
|
import { Tabs, TabItem } from '@opentiny/vue'
|
||||||
import { getMergeMeta } from '@opentiny/tiny-engine-meta-register'
|
import { META_APP as PLUGIN_NAME, getMergeMeta } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { PluginPanel } from '@opentiny/tiny-engine-common'
|
import { PluginPanel } from '@opentiny/tiny-engine-common'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -83,6 +80,7 @@ export default {
|
||||||
const title = ref(props.registryData?.title)
|
const title = ref(props.registryData?.title)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
title,
|
title,
|
||||||
activeName,
|
activeName,
|
||||||
defaultComponent,
|
defaultComponent,
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ export default {
|
||||||
title: '页面',
|
title: '页面',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
icon: 'plugin-icon-page',
|
icon: 'plugin-icon-page',
|
||||||
align: 'top'
|
align: 'leftTop'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="plugin-page">
|
<div class="plugin-page">
|
||||||
<plugin-panel :title="title" @close="pluginPanelClosed" :docsUrl="docsUrl" :isShowDocsIcon="true">
|
<plugin-panel
|
||||||
|
:title="title"
|
||||||
|
:fixed-name="PLUGIN_NAME.AppManage"
|
||||||
|
:fixedPanels="fixedPanels"
|
||||||
|
@close="pluginPanelClosed"
|
||||||
|
:docsUrl="docsUrl"
|
||||||
|
:isShowDocsIcon="true"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<svg-button
|
<svg-button
|
||||||
class="add-folder-icon"
|
class="add-folder-icon"
|
||||||
|
|
@ -36,7 +43,7 @@
|
||||||
|
|
||||||
<script lang="jsx">
|
<script lang="jsx">
|
||||||
import { reactive, ref, watchEffect, provide } from 'vue'
|
import { reactive, ref, watchEffect, provide } from 'vue'
|
||||||
import { useCanvas, usePage, useHelp, useModal, useNotify } from '@opentiny/tiny-engine-meta-register'
|
import { useCanvas, usePage, useHelp, useModal, useNotify, useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { PluginPanel, SvgButton } from '@opentiny/tiny-engine-common'
|
import { PluginPanel, SvgButton } from '@opentiny/tiny-engine-common'
|
||||||
import { extend } from '@opentiny/vue-renderless/common/object'
|
import { extend } from '@opentiny/vue-renderless/common/object'
|
||||||
import PageSetting, { openPageSettingPanel, closePageSettingPanel } from './PageSetting.vue'
|
import PageSetting, { openPageSettingPanel, closePageSettingPanel } from './PageSetting.vue'
|
||||||
|
|
@ -67,13 +74,25 @@ export default {
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '页面'
|
default: '页面'
|
||||||
|
},
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup() {
|
emits: ['close'],
|
||||||
|
setup(props, { emit }) {
|
||||||
const { confirm } = useModal()
|
const { confirm } = useModal()
|
||||||
const { pageState } = useCanvas()
|
const { pageState } = useCanvas()
|
||||||
const { pageSettingState, getDefaultPage, isTemporaryPage, initCurrentPageData } = usePage()
|
const { pageSettingState, getDefaultPage, isTemporaryPage, initCurrentPageData } = usePage()
|
||||||
|
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const pageTreeRef = ref(null)
|
const pageTreeRef = ref(null)
|
||||||
const ROOT_ID = pageSettingState.ROOT_ID
|
const ROOT_ID = pageSettingState.ROOT_ID
|
||||||
const docsUrl = useHelp().getDocsUrl('page')
|
const docsUrl = useHelp().getDocsUrl('page')
|
||||||
|
|
@ -169,6 +188,7 @@ export default {
|
||||||
provide('openSettingPanel', openSettingPanel)
|
provide('openSettingPanel', openSettingPanel)
|
||||||
|
|
||||||
const pluginPanelClosed = () => {
|
const pluginPanelClosed = () => {
|
||||||
|
emit('close')
|
||||||
closePageSettingPanel()
|
closePageSettingPanel()
|
||||||
closeFolderSettingPanel()
|
closeFolderSettingPanel()
|
||||||
}
|
}
|
||||||
|
|
@ -178,6 +198,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
state,
|
state,
|
||||||
pageState,
|
pageState,
|
||||||
openNewPage,
|
openNewPage,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-setting v-if="isShow" :title="state.title" class="pageFolder-plugin-setting">
|
<plugin-setting
|
||||||
|
v-if="isShow"
|
||||||
|
:fixed-name="PLUGIN_NAME.AppManage"
|
||||||
|
:align="align"
|
||||||
|
:title="state.title"
|
||||||
|
class="pageFolder-plugin-setting"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<button-group>
|
<button-group>
|
||||||
<tiny-button type="primary" @click="saveFolderSetting">保存</tiny-button>
|
<tiny-button type="primary" @click="saveFolderSetting">保存</tiny-button>
|
||||||
|
|
@ -27,11 +33,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref, computed } from 'vue'
|
||||||
import { Button, Collapse, CollapseItem } from '@opentiny/vue'
|
import { Button, Collapse, CollapseItem } from '@opentiny/vue'
|
||||||
import { PluginSetting, SvgButton, ButtonGroup } from '@opentiny/tiny-engine-common'
|
import { PluginSetting, SvgButton, ButtonGroup } from '@opentiny/tiny-engine-common'
|
||||||
import {
|
import {
|
||||||
usePage,
|
usePage,
|
||||||
|
useLayout,
|
||||||
useModal,
|
useModal,
|
||||||
useNotify,
|
useNotify,
|
||||||
getMergeRegistry,
|
getMergeRegistry,
|
||||||
|
|
@ -83,6 +90,9 @@ export default {
|
||||||
const pageGeneral = registry.components.PageGeneral
|
const pageGeneral = registry.components.PageGeneral
|
||||||
const folderGeneralRef = ref(null)
|
const folderGeneralRef = ref(null)
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.AppManage))
|
||||||
|
|
||||||
const closeFolderSetting = () => {
|
const closeFolderSetting = () => {
|
||||||
if (isEqual(pageSettingState.currentPageData, pageSettingState.currentPageDataCopy)) {
|
if (isEqual(pageSettingState.currentPageData, pageSettingState.currentPageDataCopy)) {
|
||||||
closeFolderSettingPanel()
|
closeFolderSettingPanel()
|
||||||
|
|
@ -197,6 +207,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
|
PLUGIN_NAME,
|
||||||
saveFolderSetting,
|
saveFolderSetting,
|
||||||
deleteFolder: throttle(5000, true, deleteFolder),
|
deleteFolder: throttle(5000, true, deleteFolder),
|
||||||
pageGeneral,
|
pageGeneral,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-setting v-if="isShow" :title="state.title" class="page-plugin-setting">
|
<plugin-setting
|
||||||
|
v-if="isShow"
|
||||||
|
:fixed-name="PLUGIN_NAME.AppManage"
|
||||||
|
:align="align"
|
||||||
|
:title="state.title"
|
||||||
|
class="page-plugin-setting"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<button-group>
|
<button-group>
|
||||||
<tiny-button type="primary" @click="savePageSetting">保存</tiny-button>
|
<tiny-button type="primary" @click="savePageSetting">保存</tiny-button>
|
||||||
|
|
@ -54,7 +60,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="jsx">
|
<script lang="jsx">
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref, computed } from 'vue'
|
||||||
import { Button, Collapse, CollapseItem, Input } from '@opentiny/vue'
|
import { Button, Collapse, CollapseItem, Input } from '@opentiny/vue'
|
||||||
import { PluginSetting, ButtonGroup, SvgButton, LifeCycles } from '@opentiny/tiny-engine-common'
|
import { PluginSetting, ButtonGroup, SvgButton, LifeCycles } from '@opentiny/tiny-engine-common'
|
||||||
import {
|
import {
|
||||||
|
|
@ -136,6 +142,9 @@ export default {
|
||||||
const beforeCreatePage = registry?.options?.beforeCreatePage
|
const beforeCreatePage = registry?.options?.beforeCreatePage
|
||||||
const pageGeneralRef = ref(null)
|
const pageGeneralRef = ref(null)
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginByLayout } = useLayout()
|
||||||
|
const align = computed(() => getPluginByLayout(PLUGIN_NAME.AppManage))
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
activeName: Object.values(PAGE_SETTING_SESSION),
|
activeName: Object.values(PAGE_SETTING_SESSION),
|
||||||
title: '页面设置',
|
title: '页面设置',
|
||||||
|
|
@ -398,6 +407,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
align,
|
||||||
|
PLUGIN_NAME,
|
||||||
state,
|
state,
|
||||||
isShow,
|
isShow,
|
||||||
savePageSetting,
|
savePageSetting,
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,5 @@ export default {
|
||||||
title: 'AI对话框',
|
title: 'AI对话框',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
icon: RobotIcon,
|
icon: RobotIcon,
|
||||||
align: 'bottom'
|
align: 'leftBottom'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,7 @@ export default {
|
||||||
title: '页面 Schema',
|
title: '页面 Schema',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
icon: 'plugin-icon-page-schema',
|
icon: 'plugin-icon-page-schema',
|
||||||
align: 'bottom'
|
align: 'leftBottom',
|
||||||
|
widthResizable: true,
|
||||||
|
width: 600
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,49 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="source-code" class="plugin-schema">
|
<plugin-panel
|
||||||
<div class="source-code-header">
|
id="source-code"
|
||||||
<div class="title">页面Schema</div>
|
title="页面 Schema"
|
||||||
<div class="header-title">
|
class="plugin-schema"
|
||||||
<!-- 暂时放开schema录入功能,等画布功能完善后,再打开下面一行的注释 -->
|
:fixed-name="PLUGIN_NAME.Schema"
|
||||||
<!-- <tiny-popover v-if="isEdit" placement="bottom" trigger="hover" append-to-body content="保存"> -->
|
:fixedPanels="fixedPanels"
|
||||||
<span class="icon-wrap" @click="saveSchema">
|
@close="close"
|
||||||
<i v-show="!showRed" class="red"></i>
|
>
|
||||||
<tiny-button type="primary">保存</tiny-button>
|
<template #header>
|
||||||
</span>
|
<span class="icon-wrap">
|
||||||
<tiny-popover v-show="false" placement="bottom" trigger="hover" append-to-body content="导入 Schema">
|
<i v-show="!showRed" class="red"></i>
|
||||||
<template #reference>
|
<tiny-button type="primary" @click="saveSchema">保存</tiny-button>
|
||||||
<span class="icon-wrap">
|
</span>
|
||||||
<icon-download-link></icon-download-link>
|
<tiny-popover v-show="false" placement="bottom" trigger="hover" append-to-body content="导入 Schema">
|
||||||
</span>
|
<template #reference>
|
||||||
</template>
|
<span class="icon-wrap">
|
||||||
</tiny-popover>
|
<icon-download-link></icon-download-link>
|
||||||
<close-icon @close="close"></close-icon>
|
</span>
|
||||||
|
</template>
|
||||||
|
</tiny-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #content>
|
||||||
|
<div class="source-code-content">
|
||||||
|
<monaco-editor
|
||||||
|
ref="container"
|
||||||
|
class="code-edit-content"
|
||||||
|
:value="state.pageData"
|
||||||
|
:options="options"
|
||||||
|
@change="editorChange"
|
||||||
|
@shortcutSave="saveSchema"
|
||||||
|
></monaco-editor>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="source-code-footer">
|
||||||
<div class="source-code-content">
|
<button>导入 Schema</button>
|
||||||
<monaco-editor
|
</div>
|
||||||
ref="container"
|
</template>
|
||||||
class="code-edit-content"
|
</plugin-panel>
|
||||||
:value="state.pageData"
|
|
||||||
:options="options"
|
|
||||||
@change="editorChange"
|
|
||||||
@shortcutSave="saveSchema"
|
|
||||||
></monaco-editor>
|
|
||||||
</div>
|
|
||||||
<div class="source-code-footer">
|
|
||||||
<button>导入 Schema</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="jsx">
|
<script lang="jsx">
|
||||||
import { nextTick, reactive, getCurrentInstance, onActivated, ref, onDeactivated } from 'vue'
|
import { nextTick, reactive, getCurrentInstance, onActivated, ref, onDeactivated, provide } from 'vue'
|
||||||
import { Popover, Button } from '@opentiny/vue'
|
import { Popover, Button } from '@opentiny/vue'
|
||||||
import { VueMonaco, CloseIcon } from '@opentiny/tiny-engine-common'
|
import { VueMonaco, PluginPanel } from '@opentiny/tiny-engine-common'
|
||||||
import { useCanvas, useModal, useNotify, useMessage } from '@opentiny/tiny-engine-meta-register'
|
import { useCanvas, useModal, useNotify, useMessage, useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { utils } from '@opentiny/tiny-engine-utils'
|
import { utils } from '@opentiny/tiny-engine-utils'
|
||||||
import { iconDownloadLink } from '@opentiny/vue-icon'
|
import { iconDownloadLink } from '@opentiny/vue-icon'
|
||||||
import { useThrottleFn } from '@vueuse/core'
|
import { useThrottleFn } from '@vueuse/core'
|
||||||
|
|
@ -51,9 +55,14 @@ export default {
|
||||||
MonacoEditor: VueMonaco,
|
MonacoEditor: VueMonaco,
|
||||||
TinyPopover: Popover,
|
TinyPopover: Popover,
|
||||||
TinyButton: Button,
|
TinyButton: Button,
|
||||||
CloseIcon,
|
PluginPanel,
|
||||||
IconDownloadLink: iconDownloadLink()
|
IconDownloadLink: iconDownloadLink()
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const app = getCurrentInstance()
|
const app = getCurrentInstance()
|
||||||
const { pageState } = useCanvas()
|
const { pageState } = useCanvas()
|
||||||
|
|
@ -63,6 +72,13 @@ export default {
|
||||||
})
|
})
|
||||||
const { subscribe, unsubscribe } = useMessage()
|
const { subscribe, unsubscribe } = useMessage()
|
||||||
|
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const isEdit = false
|
const isEdit = false
|
||||||
const showRed = ref(true)
|
const showRed = ref(true)
|
||||||
|
|
||||||
|
|
@ -148,6 +164,7 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
state,
|
state,
|
||||||
isEdit,
|
isEdit,
|
||||||
saveSchema,
|
saveSchema,
|
||||||
|
|
@ -169,57 +186,35 @@ export default {
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
#source-code {
|
#source-code {
|
||||||
width: 50vw;
|
|
||||||
height: calc(100% - var(--base-top-panel-height));
|
|
||||||
padding: 12px 0;
|
|
||||||
position: fixed;
|
|
||||||
top: var(--base-top-panel-height);
|
|
||||||
left: 41px;
|
|
||||||
background: var(--te-schema-panel-bg-color);
|
|
||||||
box-shadow: 6px 0px 3px 0px var(--te-schema-panel-shadow-color);
|
box-shadow: 6px 0px 3px 0px var(--te-schema-panel-shadow-color);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
.source-code-header {
|
|
||||||
display: flex;
|
.icon-wrap {
|
||||||
justify-content: space-between;
|
position: relative;
|
||||||
align-items: center;
|
margin-right: 6px;
|
||||||
border-bottom: 1px solid var(--te-schema-common-border-color);
|
|
||||||
margin-bottom: 12px;
|
.tiny-button {
|
||||||
padding: 0 12px 12px;
|
min-width: 40px;
|
||||||
}
|
margin-right: 2px;
|
||||||
.title {
|
height: 24px;
|
||||||
color: var(--te-schema-panel-title-text-color);
|
line-height: 24px;
|
||||||
font-weight: var(--te-base-font-weight-bold);
|
|
||||||
}
|
|
||||||
.header-title {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
.icon-wrap {
|
|
||||||
position: relative;
|
|
||||||
.tiny-button {
|
|
||||||
min-width: 40px;
|
|
||||||
margin-right: 2px;
|
|
||||||
height: 24px;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
.red {
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: var(--te-schema-dot-color);
|
|
||||||
display: block;
|
|
||||||
z-index: 100;
|
|
||||||
position: absolute;
|
|
||||||
top: -3px;
|
|
||||||
right: -4px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
& > span:not(:last-child) {
|
|
||||||
margin-right: 8px;
|
.red {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--te-schema-dot-color);
|
||||||
|
display: block;
|
||||||
|
z-index: 100;
|
||||||
|
position: absolute;
|
||||||
|
top: -3px;
|
||||||
|
right: -1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.source-code-content {
|
.source-code-content {
|
||||||
height: calc(100% - 42px);
|
height: calc(100% - 12px);
|
||||||
border: 1px solid var(--te-schema-common-border-color);
|
border: 1px solid var(--te-schema-common-border-color);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin: 0 12px;
|
margin: 0 12px;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ export default {
|
||||||
title: '页面 JS',
|
title: '页面 JS',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
icon: 'plugin-icon-js',
|
icon: 'plugin-icon-js',
|
||||||
align: 'top',
|
align: 'leftTop',
|
||||||
|
width: 600,
|
||||||
|
widthResizable: true,
|
||||||
confirm: 'close' // 当点击插件栏切换或关闭前是否需要确认, 会调用插件中confirm值指定的方法,e.g. 此处指向 close方法,会调用插件的close方法执行确认逻辑
|
confirm: 'close' // 当点击插件栏切换或关闭前是否需要确认, 会调用插件中confirm值指定的方法,e.g. 此处指向 close方法,会调用插件的close方法执行确认逻辑
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,39 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="plugin-page-js-container plugin-script">
|
<plugin-panel
|
||||||
<div class="code-edit-head">
|
title="页面 JS"
|
||||||
<div class="head-left">
|
:fixed-name="PLUGIN_NAME.Page"
|
||||||
<span class="title">页面 JS</span>
|
:fixedPanels="fixedPanels"
|
||||||
<link-button :href="docsUrl"></link-button>
|
:docsUrl="docsUrl"
|
||||||
|
:isShowDocsIcon="true"
|
||||||
|
@close="$emit('close')"
|
||||||
|
class="plugin-page-js-container plugin-script"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span class="icon-wrap">
|
||||||
|
<i v-show="state.isChanged" class="red"></i>
|
||||||
|
<tiny-button type="primary" @click="saveMethods">保存</tiny-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<div class="code-edit-content">
|
||||||
|
<monaco-editor
|
||||||
|
ref="monaco"
|
||||||
|
:value="state.script"
|
||||||
|
:options="options"
|
||||||
|
@change="change"
|
||||||
|
@editorDidMount="editorDidMount"
|
||||||
|
@shortcutSave="saveMethods"
|
||||||
|
></monaco-editor>
|
||||||
</div>
|
</div>
|
||||||
<div class="head-right">
|
</template>
|
||||||
<tiny-button type="primary" class="save-btn" @click="saveMethods">
|
</plugin-panel>
|
||||||
<span>保存</span>
|
|
||||||
<span v-show="state.isChanged" class="dots"></span>
|
|
||||||
</tiny-button>
|
|
||||||
<close-icon @close="close"></close-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="code-edit-content">
|
|
||||||
<monaco-editor
|
|
||||||
ref="monaco"
|
|
||||||
:value="state.script"
|
|
||||||
:options="options"
|
|
||||||
@change="change"
|
|
||||||
@editorDidMount="editorDidMount"
|
|
||||||
@shortcutSave="saveMethods"
|
|
||||||
></monaco-editor>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onBeforeUnmount } from 'vue'
|
import { onBeforeUnmount, reactive, provide } from 'vue'
|
||||||
import { Button } from '@opentiny/vue'
|
import { Button } from '@opentiny/vue'
|
||||||
import { VueMonaco, CloseIcon, LinkButton } from '@opentiny/tiny-engine-common'
|
import { VueMonaco, PluginPanel } from '@opentiny/tiny-engine-common'
|
||||||
import { useHelp } from '@opentiny/tiny-engine-meta-register'
|
import { useHelp, useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
import { initCompletion } from '@opentiny/tiny-engine-common/js/completion'
|
import { initCompletion } from '@opentiny/tiny-engine-common/js/completion'
|
||||||
import { initLinter } from '@opentiny/tiny-engine-common/js/linter'
|
import { initLinter } from '@opentiny/tiny-engine-common/js/linter'
|
||||||
import useMethod, { saveMethod, highlightMethod, getMethodNameList, getMethods } from './js/method'
|
import useMethod, { saveMethod, highlightMethod, getMethodNameList, getMethods } from './js/method'
|
||||||
|
|
@ -46,14 +49,25 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
MonacoEditor: VueMonaco,
|
MonacoEditor: VueMonaco,
|
||||||
TinyButton: Button,
|
TinyButton: Button,
|
||||||
CloseIcon,
|
PluginPanel
|
||||||
LinkButton
|
},
|
||||||
|
props: {
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
},
|
},
|
||||||
emits: ['close'],
|
emits: ['close'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const docsUrl = useHelp().getDocsUrl('script')
|
const docsUrl = useHelp().getDocsUrl('script')
|
||||||
const { state, monaco, change, close, saveMethods } = useMethod({ emit })
|
const { state, monaco, change, close, saveMethods } = useMethod({ emit })
|
||||||
|
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
language: 'javascript',
|
language: 'javascript',
|
||||||
minimap: {
|
minimap: {
|
||||||
|
|
@ -105,6 +119,7 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
state,
|
state,
|
||||||
monaco,
|
monaco,
|
||||||
options,
|
options,
|
||||||
|
|
@ -120,59 +135,36 @@ export default {
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.plugin-page-js-container {
|
.plugin-page-js-container {
|
||||||
width: 50vw;
|
|
||||||
height: 100%;
|
|
||||||
background: var(--te-plugin-js-panel-bg-color);
|
|
||||||
box-shadow: 6px 0px 3px 0px var(--te-plugin-js-panel-shadow-color);
|
box-shadow: 6px 0px 3px 0px var(--te-plugin-js-panel-shadow-color);
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.code-edit-head {
|
.icon-wrap {
|
||||||
display: flex;
|
position: relative;
|
||||||
justify-content: space-between;
|
margin-right: 6px;
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid var(--te-plugin-js-common-border-color);
|
|
||||||
padding: 12px 0;
|
|
||||||
|
|
||||||
.head-left {
|
.tiny-button {
|
||||||
padding-left: 12px;
|
min-width: 40px;
|
||||||
display: flex;
|
margin-right: 2px;
|
||||||
align-items: center;
|
height: 24px;
|
||||||
.title {
|
line-height: 24px;
|
||||||
color: var(--te-plugin-js-panel-title-text-color);
|
|
||||||
font-weight: var(--te-base-font-weight-bold);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.head-right {
|
.red {
|
||||||
margin-right: 12px;
|
width: 6px;
|
||||||
display: flex;
|
height: 6px;
|
||||||
align-items: center;
|
border-radius: 50%;
|
||||||
|
background: var(--te-plugin-js-dot-color);
|
||||||
.save-btn {
|
display: block;
|
||||||
min-width: 40px;
|
z-index: 100;
|
||||||
margin-right: 8px;
|
position: absolute;
|
||||||
height: 24px;
|
top: -3px;
|
||||||
line-height: 24px;
|
right: -1px;
|
||||||
.dots {
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
background: var(--te-plugin-js-dot-color);
|
|
||||||
border-radius: 50%;
|
|
||||||
position: absolute;
|
|
||||||
top: 9px;
|
|
||||||
right: 34px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.code-edit-content {
|
.code-edit-content {
|
||||||
padding: 12px;
|
padding: 0 12px;
|
||||||
height: calc(100% - 54px);
|
height: calc(100% - 12px);
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
border: 1px solid var(--te-plugin-js-common-border-color);
|
border: 1px solid var(--te-plugin-js-common-border-color);
|
||||||
|
|
@ -181,6 +173,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.help-box) {
|
:deep(.help-box) {
|
||||||
height: auto;
|
height: auto;
|
||||||
#help-icon {
|
#help-icon {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@ export default {
|
||||||
id: 'engine.plugins.state',
|
id: 'engine.plugins.state',
|
||||||
title: '状态管理',
|
title: '状态管理',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
align: 'top',
|
align: 'leftTop',
|
||||||
icon: 'plugin-icon-var'
|
icon: 'plugin-icon-var'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,78 +1,84 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="data-source" class="plugin-state">
|
<plugin-panel
|
||||||
<div class="data-source-left-panel">
|
id="data-source"
|
||||||
<div class="title">
|
title="状态管理"
|
||||||
<span>状态管理</span>
|
class="plugin-state"
|
||||||
<link-button :href="docsUrl"></link-button>
|
:fixed-name="PLUGIN_NAME.State"
|
||||||
<close-icon @close="closePanel"></close-icon>
|
:fixedPanels="fixedPanels"
|
||||||
|
:docsUrl="docsUrl"
|
||||||
|
:isShowDocsIcon="true"
|
||||||
|
@close="closePanel"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<div class="data-source-left-panel">
|
||||||
|
<tiny-tabs v-model="activeName" @click="tabClick" tab-style="button-card">
|
||||||
|
<tiny-tab-item :name="STATE.CURRENT_STATE" :title="isBlock ? '区块状态' : '页面状态'"></tiny-tab-item>
|
||||||
|
<tiny-tab-item :name="STATE.GLOBAL_STATE" title="应用状态"></tiny-tab-item>
|
||||||
|
</tiny-tabs>
|
||||||
|
<tiny-search
|
||||||
|
:modelValue="query"
|
||||||
|
class="left-filter"
|
||||||
|
placeholder="请输入搜索条件"
|
||||||
|
clearable
|
||||||
|
@update:modelValue="search"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<tiny-icon-search />
|
||||||
|
</template>
|
||||||
|
</tiny-search>
|
||||||
|
<div class="add-btn">
|
||||||
|
<tiny-button @click="openPanel(OPTION_TYPE.ADD)">
|
||||||
|
<svg-icon name="add" class="add-btn-icon"></svg-icon>
|
||||||
|
<span class="add-btn-text">{{ activeName === STATE.CURRENT_STATE ? '添加变量' : '添加全局变量' }}</span>
|
||||||
|
</tiny-button>
|
||||||
|
</div>
|
||||||
|
<data-source-list
|
||||||
|
:modelValue="Object.keys(state.dataSource)"
|
||||||
|
:stateScope="activeName"
|
||||||
|
:query="query"
|
||||||
|
:selectedKey="selectedKey"
|
||||||
|
@openPanel="openPanel"
|
||||||
|
@remove="remove"
|
||||||
|
@removeStore="removeStore"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<tiny-tabs v-model="activeName" @click="tabClick" tab-style="button-card">
|
<div class="data-source-right-panel" v-if="isPanelShow" :style="alignStyle">
|
||||||
<tiny-tab-item :name="STATE.CURRENT_STATE" :title="isBlock ? '区块状态' : '页面状态'"></tiny-tab-item>
|
<div class="header">
|
||||||
<tiny-tab-item :name="STATE.GLOBAL_STATE" title="应用状态"></tiny-tab-item>
|
<span>{{ addDataSource }}</span>
|
||||||
</tiny-tabs>
|
<span class="options-wrap">
|
||||||
<tiny-search
|
<tiny-button type="primary" @click="confirm">保存</tiny-button>
|
||||||
:modelValue="query"
|
<close-icon @close="cancel"></close-icon>
|
||||||
class="left-filter"
|
</span>
|
||||||
placeholder="请输入搜索条件"
|
</div>
|
||||||
clearable
|
<create-variable
|
||||||
@update:modelValue="search"
|
v-if="activeName === STATE.CURRENT_STATE"
|
||||||
>
|
ref="variableRef"
|
||||||
<template #prefix>
|
:dataSource="state.dataSource"
|
||||||
<tiny-icon-search />
|
:flag="flag"
|
||||||
</template>
|
:updateKey="updateKey"
|
||||||
</tiny-search>
|
:createData="state.createData"
|
||||||
<div class="add-btn">
|
@nameInput="updateName"
|
||||||
<tiny-button @click="openPanel(OPTION_TYPE.ADD)">
|
@close="cancel"
|
||||||
<svg-icon name="add" class="add-btn-icon"></svg-icon>
|
@mouseleave="onMouseLeaveVariable"
|
||||||
<span class="add-btn-text">{{ activeName === STATE.CURRENT_STATE ? '添加变量' : '添加全局变量' }}</span>
|
/>
|
||||||
</tiny-button>
|
<create-store
|
||||||
|
v-if="activeName === STATE.GLOBAL_STATE"
|
||||||
|
ref="storeRef"
|
||||||
|
:dataSource="state.dataSource"
|
||||||
|
:flag="flag"
|
||||||
|
:updateKey="updateKey"
|
||||||
|
:storeData="state.createData"
|
||||||
|
@nameInput="validName"
|
||||||
|
@close="cancel"
|
||||||
|
@mouseleave="onMouseLeaveStore"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<data-source-list
|
</template>
|
||||||
:modelValue="Object.keys(state.dataSource)"
|
</plugin-panel>
|
||||||
:stateScope="activeName"
|
|
||||||
:query="query"
|
|
||||||
:selectedKey="selectedKey"
|
|
||||||
@openPanel="openPanel"
|
|
||||||
@remove="remove"
|
|
||||||
@removeStore="removeStore"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div v-if="isPanelShow" class="data-source-right-panel">
|
|
||||||
<div class="header">
|
|
||||||
<span>{{ addDataSource }}</span>
|
|
||||||
<span class="options-wrap">
|
|
||||||
<tiny-button type="primary" @click="confirm">保存</tiny-button>
|
|
||||||
<close-icon @close="cancel"></close-icon>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<create-variable
|
|
||||||
v-if="activeName === STATE.CURRENT_STATE"
|
|
||||||
ref="variableRef"
|
|
||||||
:dataSource="state.dataSource"
|
|
||||||
:flag="flag"
|
|
||||||
:updateKey="updateKey"
|
|
||||||
:createData="state.createData"
|
|
||||||
@nameInput="updateName"
|
|
||||||
@close="cancel"
|
|
||||||
@mouseleave="onMouseLeaveVariable"
|
|
||||||
/>
|
|
||||||
<create-store
|
|
||||||
v-if="activeName === STATE.GLOBAL_STATE"
|
|
||||||
ref="storeRef"
|
|
||||||
:dataSource="state.dataSource"
|
|
||||||
:flag="flag"
|
|
||||||
:updateKey="updateKey"
|
|
||||||
:storeData="state.createData"
|
|
||||||
@nameInput="validName"
|
|
||||||
@close="cancel"
|
|
||||||
@mouseleave="onMouseLeaveStore"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reactive, ref, computed, onActivated, watch } from 'vue'
|
import { reactive, ref, computed, onActivated, watch, provide } from 'vue'
|
||||||
import { Button, Search, Tabs, TabItem } from '@opentiny/vue'
|
import { Button, Search, Tabs, TabItem } from '@opentiny/vue'
|
||||||
import {
|
import {
|
||||||
useCanvas,
|
useCanvas,
|
||||||
|
|
@ -80,13 +86,14 @@ import {
|
||||||
useResource,
|
useResource,
|
||||||
useNotify,
|
useNotify,
|
||||||
useHelp,
|
useHelp,
|
||||||
|
useLayout,
|
||||||
getMetaApi,
|
getMetaApi,
|
||||||
META_APP,
|
META_APP,
|
||||||
META_SERVICE
|
META_SERVICE
|
||||||
} from '@opentiny/tiny-engine-meta-register'
|
} from '@opentiny/tiny-engine-meta-register'
|
||||||
import { getCommentByKey } from '@opentiny/tiny-engine-common/js/comment'
|
import { getCommentByKey } from '@opentiny/tiny-engine-common/js/comment'
|
||||||
import { iconSearch } from '@opentiny/vue-icon'
|
import { iconSearch } from '@opentiny/vue-icon'
|
||||||
import { CloseIcon, LinkButton } from '@opentiny/tiny-engine-common'
|
import { CloseIcon, PluginPanel } from '@opentiny/tiny-engine-common'
|
||||||
import DataSourceList from './DataSourceList.vue'
|
import DataSourceList from './DataSourceList.vue'
|
||||||
import CreateVariable from './CreateVariable.vue'
|
import CreateVariable from './CreateVariable.vue'
|
||||||
import CreateStore from './CreateStore.vue'
|
import CreateStore from './CreateStore.vue'
|
||||||
|
|
@ -104,9 +111,14 @@ export default {
|
||||||
TinyTabs: Tabs,
|
TinyTabs: Tabs,
|
||||||
TinyTabItem: TabItem,
|
TinyTabItem: TabItem,
|
||||||
CreateStore,
|
CreateStore,
|
||||||
LinkButton,
|
PluginPanel,
|
||||||
TinyIconSearch: iconSearch()
|
TinyIconSearch: iconSearch()
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const variableRef = ref(null)
|
const variableRef = ref(null)
|
||||||
const storeRef = ref(null)
|
const storeRef = ref(null)
|
||||||
|
|
@ -131,6 +143,24 @@ export default {
|
||||||
})
|
})
|
||||||
const selectedKey = ref(null)
|
const selectedKey = ref(null)
|
||||||
|
|
||||||
|
const { PLUGIN_NAME, getPluginWidth, getPluginByLayout } = useLayout()
|
||||||
|
|
||||||
|
const firstPanelOffset = computed(() => {
|
||||||
|
return getPluginWidth(PLUGIN_NAME.State)
|
||||||
|
})
|
||||||
|
|
||||||
|
const alignStyle = computed(() => {
|
||||||
|
const panelAlign = getPluginByLayout(PLUGIN_NAME.State)
|
||||||
|
const align = panelAlign.includes('left') ? 'left' : 'right'
|
||||||
|
return `${align}: ${firstPanelOffset.value}px`
|
||||||
|
})
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
watch(activeName, () => {
|
watch(activeName, () => {
|
||||||
selectedKey.value = null
|
selectedKey.value = null
|
||||||
})
|
})
|
||||||
|
|
@ -355,6 +385,9 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
alignStyle,
|
||||||
|
firstPanelOffset,
|
||||||
|
PLUGIN_NAME,
|
||||||
isBlock,
|
isBlock,
|
||||||
isPanelShow,
|
isPanelShow,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
|
@ -420,18 +453,6 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
|
||||||
padding: 10px;
|
|
||||||
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
|
|
||||||
'Helvetica Neue', sans-serif;
|
|
||||||
color: var(--te-state-common-text-color);
|
|
||||||
font-weight: var(--te-base-font-weight-bold);
|
|
||||||
border-bottom: 1px solid var(--te-state-common-border-color-divider);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-filter {
|
.left-filter {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
|
@ -459,7 +480,6 @@ export default {
|
||||||
border-right: 1px solid var(--te-state-common-border-color-divider);
|
border-right: 1px solid var(--te-state-common-border-color-divider);
|
||||||
background: var(--te-state-common-bg-color);
|
background: var(--te-state-common-bg-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: var(--base-left-panel-width);
|
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
|
|
@ -490,7 +510,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.tiny-tabs__header) {
|
:deep(.tiny-tabs__header) {
|
||||||
padding: 8px;
|
padding: 0 8px 8px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.tiny-tabs__header .tiny-tabs__active-bar) {
|
:deep(.tiny-tabs__header .tiny-tabs__active-bar) {
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,6 @@ export default {
|
||||||
title: '大纲树',
|
title: '大纲树',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
icon: 'plugin-icon-tree',
|
icon: 'plugin-icon-tree',
|
||||||
align: 'top'
|
widthResizable: true,
|
||||||
|
align: 'leftTop'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<plugin-panel class="outlinebox plugin-tree" title="大纲树" @close="$emit('close')" ref="panelRef" tabindex="0">
|
<plugin-panel
|
||||||
<template #header>
|
tabindex="0"
|
||||||
<svg-button
|
title="大纲树"
|
||||||
class="item icon-sidebar"
|
ref="panelRef"
|
||||||
:name="panelFixed ? 'fixed-solid' : 'fixed'"
|
class="outlinebox plugin-tree"
|
||||||
:tips="panelFixed ? '解除固定面板' : '固定面板'"
|
:fixed-name="PLUGIN_NAME.OutlineTree"
|
||||||
@click="$emit('fix-panel', PLUGIN_NAME.OutlineTree)"
|
:fixedPanels="fixedPanels"
|
||||||
></svg-button>
|
@close="$emit('close')"
|
||||||
</template>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<draggable-tree
|
<draggable-tree
|
||||||
label-key="componentName"
|
label-key="componentName"
|
||||||
|
|
@ -38,8 +38,19 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reactive, watch, computed, onActivated, onDeactivated, onMounted, onBeforeUnmount, nextTick, ref } from 'vue'
|
import {
|
||||||
import { PluginPanel, SvgButton } from '@opentiny/tiny-engine-common'
|
reactive,
|
||||||
|
watch,
|
||||||
|
computed,
|
||||||
|
onActivated,
|
||||||
|
onDeactivated,
|
||||||
|
provide,
|
||||||
|
onMounted,
|
||||||
|
onBeforeUnmount,
|
||||||
|
nextTick,
|
||||||
|
ref
|
||||||
|
} from 'vue'
|
||||||
|
import { PluginPanel } from '@opentiny/tiny-engine-common'
|
||||||
import { constants } from '@opentiny/tiny-engine-utils'
|
import { constants } from '@opentiny/tiny-engine-utils'
|
||||||
import {
|
import {
|
||||||
useCanvas,
|
useCanvas,
|
||||||
|
|
@ -56,7 +67,6 @@ const { PAGE_STATUS } = constants
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
PluginPanel,
|
PluginPanel,
|
||||||
SvgButton,
|
|
||||||
DraggableTree
|
DraggableTree
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -65,7 +75,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['close', 'fix-panel'],
|
emits: ['close', 'fix-panel'],
|
||||||
setup(props) {
|
setup(props, { emit }) {
|
||||||
const { pageState } = useCanvas()
|
const { pageState } = useCanvas()
|
||||||
const { getMaterial } = useMaterial()
|
const { getMaterial } = useMaterial()
|
||||||
const { PLUGIN_NAME } = useLayout()
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
@ -76,6 +86,11 @@ export default {
|
||||||
|
|
||||||
const selectedIds = computed(() => useMultiSelect().multiSelectedStates.value.map((state) => state.id))
|
const selectedIds = computed(() => useMultiSelect().multiSelectedStates.value.map((state) => state.id))
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const filterSchema = (data) => {
|
const filterSchema = (data) => {
|
||||||
const translateChild = (data) => {
|
const translateChild = (data) => {
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ export default {
|
||||||
title: 'TinyEngine 教程',
|
title: 'TinyEngine 教程',
|
||||||
type: 'plugins',
|
type: 'plugins',
|
||||||
icon: 'plugin-icon-tutorial',
|
icon: 'plugin-icon-tutorial',
|
||||||
align: 'bottom'
|
align: 'leftBottom'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
import { isRef } from 'vue'
|
||||||
import { initHook } from './hooks'
|
import { initHook } from './hooks'
|
||||||
|
|
||||||
const vueLifeHook = [
|
const vueLifeHook = [
|
||||||
|
|
@ -161,7 +161,7 @@ export const preprocessRegistry = (registry) => {
|
||||||
|
|
||||||
export const generateRegistry = (registry) => {
|
export const generateRegistry = (registry) => {
|
||||||
Object.entries(registry).forEach(([key, value]) => {
|
Object.entries(registry).forEach(([key, value]) => {
|
||||||
if (typeof value === 'object' && value) {
|
if (typeof value === 'object' && value && !isRef(value)) {
|
||||||
const { id } = value
|
const { id } = value
|
||||||
// 如果匹配到了id,说明是元服务配置,对元服务配置做读取和写入
|
// 如果匹配到了id,说明是元服务配置,对元服务配置做读取和写入
|
||||||
if (id && key !== 'metaData') {
|
if (id && key !== 'metaData') {
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,7 @@ import './src/styles/vars.less'
|
||||||
export default {
|
export default {
|
||||||
...metaData,
|
...metaData,
|
||||||
entry,
|
entry,
|
||||||
options: {
|
options: { commonEvents },
|
||||||
commonEvents
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
BindEventsDialogSidebar,
|
BindEventsDialogSidebar,
|
||||||
BindEventsDialogContent
|
BindEventsDialogContent
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ export default {
|
||||||
id: 'engine.setting.event',
|
id: 'engine.setting.event',
|
||||||
title: '高级',
|
title: '高级',
|
||||||
type: 'setting',
|
type: 'setting',
|
||||||
align: 'left',
|
align: 'rightTop',
|
||||||
name: 'event',
|
name: 'event',
|
||||||
icon: ''
|
icon: 'target'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,44 @@
|
||||||
<template>
|
<template>
|
||||||
<tiny-collapse v-model="activeNames">
|
<plugin-panel
|
||||||
<tiny-collapse-item title="事件绑定" name="bindEvent">
|
title="高级"
|
||||||
<bind-events></bind-events>
|
:fixed-panels="fixedPanels"
|
||||||
</tiny-collapse-item>
|
:fixed-name="PLUGIN_NAME.Event"
|
||||||
<tiny-collapse-item title="高级配置" name="advancedConfig">
|
:header-margin-bottom="0"
|
||||||
<advance-config></advance-config>
|
@close="$emit('close')"
|
||||||
</tiny-collapse-item>
|
>
|
||||||
</tiny-collapse>
|
<template #content>
|
||||||
|
<tiny-collapse v-model="activeNames">
|
||||||
|
<tiny-collapse-item title="事件绑定" name="bindEvent">
|
||||||
|
<bind-events></bind-events>
|
||||||
|
</tiny-collapse-item>
|
||||||
|
<tiny-collapse-item title="高级配置" name="advancedConfig">
|
||||||
|
<advance-config></advance-config>
|
||||||
|
</tiny-collapse-item>
|
||||||
|
</tiny-collapse>
|
||||||
|
</template>
|
||||||
|
</plugin-panel>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref, reactive, provide, defineProps, defineEmits } from 'vue'
|
||||||
import { Collapse as TinyCollapse, CollapseItem as TinyCollapseItem } from '@opentiny/vue'
|
import { Collapse as TinyCollapse, CollapseItem as TinyCollapseItem } from '@opentiny/vue'
|
||||||
import BindEvents from './components/BindEvents.vue'
|
import BindEvents from './components/BindEvents.vue'
|
||||||
import AdvanceConfig from './components/AdvanceConfig.vue'
|
import AdvanceConfig from './components/AdvanceConfig.vue'
|
||||||
|
import { PluginPanel } from '@opentiny/tiny-engine-common'
|
||||||
|
import { useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
|
|
||||||
const activeNames = ref(['bindEvent', 'advancedConfig'])
|
const activeNames = ref(['bindEvent', 'advancedConfig'])
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
fixedPanels: Array
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits([])
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('panelState', panelState)
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ export default {
|
||||||
id: 'engine.setting.props',
|
id: 'engine.setting.props',
|
||||||
title: '属性',
|
title: '属性',
|
||||||
type: 'setting',
|
type: 'setting',
|
||||||
align: 'left',
|
align: 'rightTop',
|
||||||
name: 'props',
|
name: 'props',
|
||||||
icon: ''
|
icon: 'form'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<config-render :data="properties">
|
<plugin-panel
|
||||||
<template #prefix="{ data }">
|
title="属性"
|
||||||
<block-link-field v-if="isBlock" :data="data"></block-link-field>
|
:fixed-panels="fixedPanels"
|
||||||
|
:fixed-name="PLUGIN_NAME.Props"
|
||||||
|
:show-bottom-border="showEmptyTips"
|
||||||
|
@close="$emit('close')"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<config-render :data="properties">
|
||||||
|
<template #prefix="{ data }">
|
||||||
|
<block-link-field v-if="isBlock" :data="data"></block-link-field>
|
||||||
|
</template>
|
||||||
|
</config-render>
|
||||||
|
<block-description v-if="isBlock" class="block-description"> </block-description>
|
||||||
|
<empty :showEmptyTips="showEmptyTips"></empty>
|
||||||
</template>
|
</template>
|
||||||
</config-render>
|
</plugin-panel>
|
||||||
<block-description v-if="isBlock" class="block-description"> </block-description>
|
|
||||||
<empty :showEmptyTips="showEmptyTips"></empty>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed, watchEffect, ref } from 'vue'
|
import { computed, watchEffect, ref, reactive, provide } from 'vue'
|
||||||
import { ConfigRender, BlockDescription, BlockLinkField } from '@opentiny/tiny-engine-common'
|
import { ConfigRender, BlockDescription, BlockLinkField, PluginPanel } from '@opentiny/tiny-engine-common'
|
||||||
import { useCanvas, useProperty } from '@opentiny/tiny-engine-meta-register'
|
import { useCanvas, useProperty, useLayout } from '@opentiny/tiny-engine-meta-register'
|
||||||
import Empty from './components/Empty.vue'
|
import Empty from './components/Empty.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -19,13 +29,21 @@ export default {
|
||||||
ConfigRender,
|
ConfigRender,
|
||||||
BlockLinkField,
|
BlockLinkField,
|
||||||
BlockDescription,
|
BlockDescription,
|
||||||
Empty
|
Empty,
|
||||||
|
PluginPanel
|
||||||
},
|
},
|
||||||
setup() {
|
setup(props, { emit }) {
|
||||||
const { pageState } = useCanvas()
|
const { pageState } = useCanvas()
|
||||||
const { properties } = useProperty().getProperty({ pageState })
|
const { properties } = useProperty().getProperty({ pageState })
|
||||||
const showEmptyTips = ref(false)
|
const showEmptyTips = ref(false)
|
||||||
|
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const isBlock = computed(() => pageState.isBlock)
|
const isBlock = computed(() => pageState.isBlock)
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
|
|
@ -33,6 +51,7 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
PLUGIN_NAME,
|
||||||
isBlock,
|
isBlock,
|
||||||
properties,
|
properties,
|
||||||
showEmptyTips
|
showEmptyTips
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,6 @@ export default {
|
||||||
title: '样式',
|
title: '样式',
|
||||||
name: 'style',
|
name: 'style',
|
||||||
type: 'setting',
|
type: 'setting',
|
||||||
align: 'left',
|
align: 'rightTop',
|
||||||
icon: ''
|
icon: 'display-inline'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,75 +1,87 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="style-editor">
|
<plugin-panel
|
||||||
<div class="line-style">
|
title="样式"
|
||||||
<span class="line-text"> 行内样式 </span>
|
:fixed-panels="fixedPanels"
|
||||||
<div class="inline-style">
|
:fixed-name="PLUGIN_NAME.Styles"
|
||||||
<component
|
:is-show-collapse-icon="true"
|
||||||
:is="CodeConfigurator"
|
:show-bottom-border="true"
|
||||||
v-if="state.lineStyleDisable"
|
@updateCollapseStatus="updateCollapseStatus"
|
||||||
:buttonShowContent="true"
|
@close="$emit('close')"
|
||||||
:modelValue="state.styleContent"
|
>
|
||||||
title="编辑行内样式"
|
<template #content>
|
||||||
:button-text="state.inlineBtnText"
|
<div class="style-editor">
|
||||||
language="css"
|
<div class="line-style">
|
||||||
single
|
<span class="line-text"> 行内样式 </span>
|
||||||
@save="save"
|
<div class="inline-style">
|
||||||
></component>
|
<component
|
||||||
<div v-if="!state.lineStyleDisable">
|
:is="CodeConfigurator"
|
||||||
<tiny-input v-model="state.propertiesList" class="inline-bind-style"> </tiny-input>
|
v-if="state.lineStyleDisable"
|
||||||
|
:buttonShowContent="true"
|
||||||
|
:modelValue="state.styleContent"
|
||||||
|
title="编辑行内样式"
|
||||||
|
:button-text="state.inlineBtnText"
|
||||||
|
language="css"
|
||||||
|
single
|
||||||
|
@save="save"
|
||||||
|
></component>
|
||||||
|
<div v-if="!state.lineStyleDisable">
|
||||||
|
<tiny-input v-model="state.propertiesList" class="inline-bind-style"> </tiny-input>
|
||||||
|
</div>
|
||||||
|
<component
|
||||||
|
:is="VariableConfigurator"
|
||||||
|
ref="bindVariable"
|
||||||
|
:model-value="state.bindModelValue"
|
||||||
|
name="advance"
|
||||||
|
@update:modelValue="setConfig"
|
||||||
|
>
|
||||||
|
</component>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<component
|
|
||||||
:is="VariableConfigurator"
|
|
||||||
ref="bindVariable"
|
|
||||||
:model-value="state.bindModelValue"
|
|
||||||
name="advance"
|
|
||||||
@update:modelValue="setConfig"
|
|
||||||
>
|
|
||||||
</component>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<class-names-container></class-names-container>
|
||||||
</div>
|
<tiny-collapse v-model="activeNames" @change="handoverGroup">
|
||||||
<class-names-container></class-names-container>
|
<tiny-collapse-item title="布局" name="layout">
|
||||||
<tiny-collapse v-model="activeNames" @change="handoverGroup">
|
<layout-group :display="state.style.display" @update="updateStyle" />
|
||||||
<tiny-collapse-item title="布局" name="layout">
|
<flex-box v-if="state.style.display === 'flex'" :style="state.style" @update="updateStyle"></flex-box>
|
||||||
<layout-group :display="state.style.display" @update="updateStyle" />
|
<grid-box v-if="state.style.display === 'grid'" :style="state.style" @update="updateStyle"></grid-box>
|
||||||
<flex-box v-if="state.style.display === 'flex'" :style="state.style" @update="updateStyle"></flex-box>
|
</tiny-collapse-item>
|
||||||
<grid-box v-if="state.style.display === 'grid'" :style="state.style" @update="updateStyle"></grid-box>
|
|
||||||
</tiny-collapse-item>
|
|
||||||
|
|
||||||
<tiny-collapse-item title="间距" name="spacing">
|
<tiny-collapse-item title="间距" name="spacing">
|
||||||
<spacing-group :style="state.style" @update="updateStyle" />
|
<spacing-group :style="state.style" @update="updateStyle" />
|
||||||
</tiny-collapse-item>
|
</tiny-collapse-item>
|
||||||
|
|
||||||
<tiny-collapse-item title="尺寸" name="size">
|
<tiny-collapse-item title="尺寸" name="size">
|
||||||
<size-group :style="state.style" @update="updateStyle" />
|
<size-group :style="state.style" @update="updateStyle" />
|
||||||
</tiny-collapse-item>
|
</tiny-collapse-item>
|
||||||
|
|
||||||
<tiny-collapse-item title="定位" name="position">
|
<tiny-collapse-item title="定位" name="position">
|
||||||
<position-group :style="state.style" @update="updateStyle" />
|
<position-group :style="state.style" @update="updateStyle" />
|
||||||
</tiny-collapse-item>
|
</tiny-collapse-item>
|
||||||
|
|
||||||
<tiny-collapse-item title="文本" name="typography">
|
<tiny-collapse-item title="文本" name="typography">
|
||||||
<typography-group :style="state.style" @update="updateStyle" />
|
<typography-group :style="state.style" @update="updateStyle" />
|
||||||
</tiny-collapse-item>
|
</tiny-collapse-item>
|
||||||
|
|
||||||
<tiny-collapse-item title="背景" name="backgrounds">
|
<tiny-collapse-item title="背景" name="backgrounds">
|
||||||
<background-group :style="state.style" @update="updateStyle" />
|
<background-group :style="state.style" @update="updateStyle" />
|
||||||
</tiny-collapse-item>
|
</tiny-collapse-item>
|
||||||
|
|
||||||
<tiny-collapse-item title="边框" name="borders">
|
<tiny-collapse-item title="边框" name="borders">
|
||||||
<border-group :style="state.style" @update="updateStyle" />
|
<border-group :style="state.style" @update="updateStyle" />
|
||||||
</tiny-collapse-item>
|
</tiny-collapse-item>
|
||||||
|
|
||||||
<tiny-collapse-item title="效果" name="effects" class="effects-style">
|
<tiny-collapse-item title="效果" name="effects" class="effects-style">
|
||||||
<effect-group :style="state.style" @update="updateStyle" />
|
<effect-group :style="state.style" @update="updateStyle" />
|
||||||
</tiny-collapse-item>
|
</tiny-collapse-item>
|
||||||
</tiny-collapse>
|
</tiny-collapse>
|
||||||
|
</template>
|
||||||
|
</plugin-panel>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { watch, inject, ref } from 'vue'
|
import { watch, ref, reactive, provide } from 'vue'
|
||||||
import { Collapse, CollapseItem, Input } from '@opentiny/vue'
|
import { Collapse, CollapseItem, Input } from '@opentiny/vue'
|
||||||
import { useHistory, useCanvas, useProperties, getConfigurator } from '@opentiny/tiny-engine-meta-register'
|
import { useLayout, useHistory, useCanvas, useProperties, getConfigurator } from '@opentiny/tiny-engine-meta-register'
|
||||||
import {
|
import {
|
||||||
SizeGroup,
|
SizeGroup,
|
||||||
LayoutGroup,
|
LayoutGroup,
|
||||||
|
|
@ -85,10 +97,12 @@ import {
|
||||||
} from './components'
|
} from './components'
|
||||||
import { CSS_TYPE } from './js/cssType'
|
import { CSS_TYPE } from './js/cssType'
|
||||||
import useStyle from './js/useStyle'
|
import useStyle from './js/useStyle'
|
||||||
|
import { PluginPanel } from '@opentiny/tiny-engine-common'
|
||||||
import { styleStrRemoveRoot } from './js/cssConvert'
|
import { styleStrRemoveRoot } from './js/cssConvert'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
PluginPanel,
|
||||||
SizeGroup,
|
SizeGroup,
|
||||||
LayoutGroup,
|
LayoutGroup,
|
||||||
FlexBox,
|
FlexBox,
|
||||||
|
|
@ -104,7 +118,12 @@ export default {
|
||||||
TinyCollapseItem: CollapseItem,
|
TinyCollapseItem: CollapseItem,
|
||||||
TinyInput: Input
|
TinyInput: Input
|
||||||
},
|
},
|
||||||
setup() {
|
props: {
|
||||||
|
fixedPanels: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
const CodeConfigurator = getConfigurator('CodeConfigurator')
|
const CodeConfigurator = getConfigurator('CodeConfigurator')
|
||||||
const VariableConfigurator = getConfigurator('VariableConfigurator')
|
const VariableConfigurator = getConfigurator('VariableConfigurator')
|
||||||
const styleCategoryGroup = [
|
const styleCategoryGroup = [
|
||||||
|
|
@ -117,13 +136,19 @@ export default {
|
||||||
'borders',
|
'borders',
|
||||||
'effects'
|
'effects'
|
||||||
]
|
]
|
||||||
const isCollapsed = inject('isCollapsed')
|
const isCollapsed = ref(false)
|
||||||
const activeNames = ref(styleCategoryGroup)
|
const activeNames = ref(styleCategoryGroup)
|
||||||
const { getCurrentSchema } = useCanvas()
|
const { getCurrentSchema } = useCanvas()
|
||||||
// 获取当前节点 style 对象
|
// 获取当前节点 style 对象
|
||||||
const { state, updateStyle } = useStyle() // updateStyle
|
const { state, updateStyle } = useStyle() // updateStyle
|
||||||
const { addHistory } = useHistory()
|
const { addHistory } = useHistory()
|
||||||
const { getSchema, setProp } = useProperties()
|
const { getSchema, setProp } = useProperties()
|
||||||
|
const { PLUGIN_NAME } = useLayout()
|
||||||
|
|
||||||
|
const panelState = reactive({
|
||||||
|
emitEvent: emit
|
||||||
|
})
|
||||||
|
provide('panelState', panelState)
|
||||||
|
|
||||||
const handoverGroup = (actives) => {
|
const handoverGroup = (actives) => {
|
||||||
if (isCollapsed.value) {
|
if (isCollapsed.value) {
|
||||||
|
|
@ -196,6 +221,10 @@ export default {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const updateCollapseStatus = (val) => {
|
||||||
|
isCollapsed.value = val
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => isCollapsed.value,
|
() => isCollapsed.value,
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -208,6 +237,8 @@ export default {
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
updateCollapseStatus,
|
||||||
|
PLUGIN_NAME,
|
||||||
CodeConfigurator,
|
CodeConfigurator,
|
||||||
VariableConfigurator,
|
VariableConfigurator,
|
||||||
state,
|
state,
|
||||||
|
|
@ -228,7 +259,7 @@ export default {
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.style-editor {
|
.style-editor {
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
padding: 12px 0 0;
|
margin-top: 12px;
|
||||||
column-gap: 8px;
|
column-gap: 8px;
|
||||||
.line-style {
|
.line-style {
|
||||||
padding: 0 8px 0 12px;
|
padding: 0 8px 0 12px;
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ body {
|
||||||
--base-bottom-panel-height: 30px;
|
--base-bottom-panel-height: 30px;
|
||||||
--base-nav-panel-width: 40px;
|
--base-nav-panel-width: 40px;
|
||||||
--base-collection-panel-width: calc(
|
--base-collection-panel-width: calc(
|
||||||
(100vw - (var(--base-left-panel-width) + var(--base-right-panel-width) + var(--base-nav-panel-width) - 1px)) / 2
|
(99vw - (var(--base-left-panel-width) + var(--base-right-panel-width) + var(--base-nav-panel-width) - 1px)) / 2
|
||||||
);
|
);
|
||||||
--base-collection-panel-full-screen-width: calc(
|
--base-collection-panel-full-screen-width: calc(
|
||||||
(100vw - (var(--base-left-panel-width) + var(--base-right-panel-width) + var(--base-nav-panel-width) - 1px))
|
(100vw - (var(--base-left-panel-width) + var(--base-right-panel-width) + var(--base-nav-panel-width) - 1px))
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ export default {
|
||||||
const showpopover = ref(false)
|
const showpopover = ref(false)
|
||||||
|
|
||||||
const themeShowType = computed(() => {
|
const themeShowType = computed(() => {
|
||||||
let filterList = THEME_DATA.value.filter((item) => ['light', 'dark'].includes(item.type)) || []
|
const filterList = THEME_DATA.value.filter((item) => ['light', 'dark'].includes(item.type)) || []
|
||||||
return THEME_DATA.value.length === filterList.length
|
return THEME_DATA.value.length === filterList.length
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,9 @@ export const BROADCAST_CHANNEL = {
|
||||||
CanvasRouterViewSetting: `tiny-lowcode-canvas-router-view-setting-${CHANNEL_UID}`
|
CanvasRouterViewSetting: `tiny-lowcode-canvas-router-view-setting-${CHANNEL_UID}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const STORAGE_KEY_FIXED_PANELS = `tiny-engine-fixed-panels-${CHANNEL_UID}`
|
export const STORAGE_KEY_LEFT_FIXED_PANELS = `tiny-engine-left-fixed-panels`
|
||||||
|
export const STORAGE_KEY_RIGHT_FIXED_PANELS = `tiny-engine-right-fixed-panels`
|
||||||
|
|
||||||
export const CANVAS_ROUTER_VIEW_SETTING_VIEW_MODE_KEY = `tiny-engine-canvas-router-view-setting-view-mode`
|
export const CANVAS_ROUTER_VIEW_SETTING_VIEW_MODE_KEY = `tiny-engine-canvas-router-view-setting-view-mode`
|
||||||
|
|
||||||
export const AUTO_SAVED = 'tiny-engine-auto-saved'
|
export const AUTO_SAVED = 'tiny-engine-auto-saved'
|
||||||
|
|
@ -161,3 +163,6 @@ export const SORT_TYPE = {
|
||||||
// 字母倒序
|
// 字母倒序
|
||||||
alphabetDesc: 'alphabetDesc'
|
alphabetDesc: 'alphabetDesc'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 插件面板默认宽度
|
||||||
|
export const PLUGIN_DEFAULT_WIDTH = 280
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue