commit
1abff21e56
@ -29,10 +29,11 @@
|
|||||||
:key="appLinkIndex"
|
:key="appLinkIndex"
|
||||||
:content="appLink.path"
|
:content="appLink.path"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
|
:show-after="300"
|
||||||
>
|
>
|
||||||
<el-button
|
<el-button
|
||||||
class="m-b-8px m-r-8px m-l-0px!"
|
class="m-b-8px m-r-8px m-l-0px!"
|
||||||
:type="isSameLink(appLink.path, activeAppLink) ? 'primary' : 'default'"
|
:type="isSameLink(appLink.path, activeAppLink.path) ? 'primary' : 'default'"
|
||||||
@click="handleAppLinkSelected(appLink)"
|
@click="handleAppLinkSelected(appLink)"
|
||||||
>
|
>
|
||||||
{{ appLink.name }}
|
{{ appLink.name }}
|
||||||
@ -63,7 +64,7 @@
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { APP_LINK_GROUP_LIST, APP_LINK_TYPE_ENUM } from './data'
|
import { APP_LINK_GROUP_LIST, APP_LINK_TYPE_ENUM, AppLink } from './data'
|
||||||
import { ButtonInstance, ScrollbarInstance } from 'element-plus'
|
import { ButtonInstance, ScrollbarInstance } from 'element-plus'
|
||||||
import { split } from 'lodash-es'
|
import { split } from 'lodash-es'
|
||||||
import ProductCategorySelect from '@/views/mall/product/category/components/ProductCategorySelect.vue'
|
import ProductCategorySelect from '@/views/mall/product/category/components/ProductCategorySelect.vue'
|
||||||
@ -74,17 +75,23 @@ defineOptions({ name: 'AppLinkSelectDialog' })
|
|||||||
// 选中的分组,默认选中第一个
|
// 选中的分组,默认选中第一个
|
||||||
const activeGroup = ref(APP_LINK_GROUP_LIST[0].name)
|
const activeGroup = ref(APP_LINK_GROUP_LIST[0].name)
|
||||||
// 选中的 APP 链接
|
// 选中的 APP 链接
|
||||||
const activeAppLink = ref('')
|
const activeAppLink = ref({} as AppLink)
|
||||||
|
|
||||||
/** 打开弹窗 */
|
/** 打开弹窗 */
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const open = (link: string) => {
|
const open = (link: string) => {
|
||||||
activeAppLink.value = link
|
activeAppLink.value.path = link
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
|
|
||||||
// 滚动到当前的链接
|
// 滚动到当前的链接
|
||||||
const group = APP_LINK_GROUP_LIST.find((group) =>
|
const group = APP_LINK_GROUP_LIST.find((group) =>
|
||||||
group.links.some((linkItem) => isSameLink(linkItem.path, link))
|
group.links.some((linkItem) => {
|
||||||
|
const sameLink = isSameLink(linkItem.path, link)
|
||||||
|
if (sameLink) {
|
||||||
|
activeAppLink.value = { ...linkItem, path: link }
|
||||||
|
}
|
||||||
|
return sameLink
|
||||||
|
})
|
||||||
)
|
)
|
||||||
if (group) {
|
if (group) {
|
||||||
// 使用 nextTick 的原因:可能 Dom 还没生成,导致滚动失败
|
// 使用 nextTick 的原因:可能 Dom 还没生成,导致滚动失败
|
||||||
@ -94,9 +101,9 @@ const open = (link: string) => {
|
|||||||
defineExpose({ open })
|
defineExpose({ open })
|
||||||
|
|
||||||
// 处理 APP 链接选中
|
// 处理 APP 链接选中
|
||||||
const handleAppLinkSelected = (appLink: any) => {
|
const handleAppLinkSelected = (appLink: AppLink) => {
|
||||||
if (!isSameLink(appLink.path, activeAppLink.value)) {
|
if (!isSameLink(appLink.path, activeAppLink.value.path)) {
|
||||||
activeAppLink.value = appLink.path
|
activeAppLink.value = appLink
|
||||||
}
|
}
|
||||||
switch (appLink.type) {
|
switch (appLink.type) {
|
||||||
case APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST:
|
case APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST:
|
||||||
@ -104,7 +111,7 @@ const handleAppLinkSelected = (appLink: any) => {
|
|||||||
detailSelectDialog.value.type = appLink.type
|
detailSelectDialog.value.type = appLink.type
|
||||||
// 返显
|
// 返显
|
||||||
detailSelectDialog.value.id =
|
detailSelectDialog.value.id =
|
||||||
getUrlNumberValue('id', 'http://127.0.0.1' + activeAppLink.value) || undefined
|
getUrlNumberValue('id', 'http://127.0.0.1' + activeAppLink.value.path) || undefined
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -114,10 +121,12 @@ const handleAppLinkSelected = (appLink: any) => {
|
|||||||
// 处理绑定值更新
|
// 处理绑定值更新
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
change: [link: string]
|
change: [link: string]
|
||||||
|
appLinkChange: [appLink: AppLink]
|
||||||
}>()
|
}>()
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
emit('change', activeAppLink.value)
|
emit('change', activeAppLink.value.path)
|
||||||
|
emit('appLinkChange', activeAppLink.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分组标题引用列表
|
// 分组标题引用列表
|
||||||
@ -127,7 +136,7 @@ const groupTitleRefs = ref<HTMLInputElement[]>([])
|
|||||||
* @param scrollTop 滚动条的位置
|
* @param scrollTop 滚动条的位置
|
||||||
*/
|
*/
|
||||||
const handleScroll = ({ scrollTop }: { scrollTop: number }) => {
|
const handleScroll = ({ scrollTop }: { scrollTop: number }) => {
|
||||||
const titleEl = groupTitleRefs.value.find((titleEl) => {
|
const titleEl = groupTitleRefs.value.find((titleEl: HTMLInputElement) => {
|
||||||
// 获取标题的位置信息
|
// 获取标题的位置信息
|
||||||
const { offsetHeight, offsetTop } = titleEl
|
const { offsetHeight, offsetTop } = titleEl
|
||||||
// 判断标题是否在可视范围内
|
// 判断标题是否在可视范围内
|
||||||
@ -146,7 +155,7 @@ const linkScrollbar = ref<ScrollbarInstance>()
|
|||||||
// 处理分组选中
|
// 处理分组选中
|
||||||
const handleGroupSelected = (group: string) => {
|
const handleGroupSelected = (group: string) => {
|
||||||
activeGroup.value = group
|
activeGroup.value = group
|
||||||
const titleRef = groupTitleRefs.value.find((item) => item.textContent === group)
|
const titleRef = groupTitleRefs.value.find((item: HTMLInputElement) => item.textContent === group)
|
||||||
if (titleRef) {
|
if (titleRef) {
|
||||||
// 滚动分组标题
|
// 滚动分组标题
|
||||||
linkScrollbar.value?.setScrollTop(titleRef.offsetTop)
|
linkScrollbar.value?.setScrollTop(titleRef.offsetTop)
|
||||||
@ -160,8 +169,8 @@ const groupBtnRefs = ref<ButtonInstance[]>([])
|
|||||||
// 自动滚动分组按钮,确保分组按钮保持在可视区域内
|
// 自动滚动分组按钮,确保分组按钮保持在可视区域内
|
||||||
const scrollToGroupBtn = (group: string) => {
|
const scrollToGroupBtn = (group: string) => {
|
||||||
const groupBtn = groupBtnRefs.value
|
const groupBtn = groupBtnRefs.value
|
||||||
.map((btn) => btn['ref'])
|
.map((btn: ButtonInstance) => btn['ref'])
|
||||||
.find((ref) => ref.textContent === group)
|
.find((ref: Node) => ref.textContent === group)
|
||||||
if (groupBtn) {
|
if (groupBtn) {
|
||||||
groupScrollbar.value?.setScrollTop(groupBtn.offsetTop)
|
groupScrollbar.value?.setScrollTop(groupBtn.offsetTop)
|
||||||
}
|
}
|
||||||
@ -184,11 +193,11 @@ const detailSelectDialog = ref<{
|
|||||||
})
|
})
|
||||||
// 处理详情选择
|
// 处理详情选择
|
||||||
const handleProductCategorySelected = (id: number) => {
|
const handleProductCategorySelected = (id: number) => {
|
||||||
const url = new URL(activeAppLink.value, 'http://127.0.0.1')
|
const url = new URL(activeAppLink.value.path, 'http://127.0.0.1')
|
||||||
// 修改 id 参数
|
// 修改 id 参数
|
||||||
url.searchParams.set('id', `${id}`)
|
url.searchParams.set('id', `${id}`)
|
||||||
// 排除域名
|
// 排除域名
|
||||||
activeAppLink.value = `${url.pathname}${url.search}`
|
activeAppLink.value.path = `${url.pathname}${url.search}`
|
||||||
// 关闭对话框
|
// 关闭对话框
|
||||||
detailSelectDialog.value.visible = false
|
detailSelectDialog.value.visible = false
|
||||||
// 重置 id
|
// 重置 id
|
||||||
|
@ -1,3 +1,20 @@
|
|||||||
|
// APP 链接分组
|
||||||
|
export interface AppLinkGroup {
|
||||||
|
// 分组名称
|
||||||
|
name: string
|
||||||
|
// 链接列表
|
||||||
|
links: AppLink[]
|
||||||
|
}
|
||||||
|
// APP 链接
|
||||||
|
export interface AppLink {
|
||||||
|
// 链接名称
|
||||||
|
name: string
|
||||||
|
// 链接地址
|
||||||
|
path: string
|
||||||
|
// 链接的类型
|
||||||
|
type?: APP_LINK_TYPE_ENUM
|
||||||
|
}
|
||||||
|
|
||||||
// APP 链接类型(需要特殊处理,例如商品详情)
|
// APP 链接类型(需要特殊处理,例如商品详情)
|
||||||
export const enum APP_LINK_TYPE_ENUM {
|
export const enum APP_LINK_TYPE_ENUM {
|
||||||
// 拼团活动
|
// 拼团活动
|
||||||
@ -243,4 +260,4 @@ export const APP_LINK_GROUP_LIST = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
] as AppLinkGroup[]
|
||||||
|
@ -37,7 +37,7 @@ const emit = defineEmits<{
|
|||||||
'update:modelValue': [link: string]
|
'update:modelValue': [link: string]
|
||||||
}>()
|
}>()
|
||||||
watch(
|
watch(
|
||||||
() => appLink,
|
() => appLink.value,
|
||||||
() => emit('update:modelValue', appLink.value)
|
() => emit('update:modelValue', appLink.value)
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
@ -0,0 +1,143 @@
|
|||||||
|
import { HotZoneItemProperty } from '@/components/DiyEditor/components/mobile/HotZone/config'
|
||||||
|
import { StyleValue } from 'vue'
|
||||||
|
|
||||||
|
// 热区的最小宽高
|
||||||
|
export const HOT_ZONE_MIN_SIZE = 100
|
||||||
|
|
||||||
|
// 控制的类型
|
||||||
|
export enum CONTROL_TYPE_ENUM {
|
||||||
|
LEFT,
|
||||||
|
TOP,
|
||||||
|
WIDTH,
|
||||||
|
HEIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义热区的控制点
|
||||||
|
export interface ControlDot {
|
||||||
|
position: string
|
||||||
|
types: CONTROL_TYPE_ENUM[]
|
||||||
|
style: StyleValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 热区的8个控制点
|
||||||
|
export const CONTROL_DOT_LIST = [
|
||||||
|
{
|
||||||
|
position: '左上角',
|
||||||
|
types: [
|
||||||
|
CONTROL_TYPE_ENUM.LEFT,
|
||||||
|
CONTROL_TYPE_ENUM.TOP,
|
||||||
|
CONTROL_TYPE_ENUM.WIDTH,
|
||||||
|
CONTROL_TYPE_ENUM.HEIGHT
|
||||||
|
],
|
||||||
|
style: { left: '-5px', top: '-5px', cursor: 'nwse-resize' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: '上方中间',
|
||||||
|
types: [CONTROL_TYPE_ENUM.TOP, CONTROL_TYPE_ENUM.HEIGHT],
|
||||||
|
style: { left: '50%', top: '-5px', cursor: 'n-resize', transform: 'translateX(-50%)' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: '右上角',
|
||||||
|
types: [CONTROL_TYPE_ENUM.TOP, CONTROL_TYPE_ENUM.WIDTH, CONTROL_TYPE_ENUM.HEIGHT],
|
||||||
|
style: { right: '-5px', top: '-5px', cursor: 'nesw-resize' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: '右侧中间',
|
||||||
|
types: [CONTROL_TYPE_ENUM.WIDTH],
|
||||||
|
style: { right: '-5px', top: '50%', cursor: 'e-resize', transform: 'translateX(-50%)' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: '右下角',
|
||||||
|
types: [CONTROL_TYPE_ENUM.WIDTH, CONTROL_TYPE_ENUM.HEIGHT],
|
||||||
|
style: { right: '-5px', bottom: '-5px', cursor: 'nwse-resize' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: '下方中间',
|
||||||
|
types: [CONTROL_TYPE_ENUM.HEIGHT],
|
||||||
|
style: { left: '50%', bottom: '-5px', cursor: 's-resize', transform: 'translateX(-50%)' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: '左下角',
|
||||||
|
types: [CONTROL_TYPE_ENUM.LEFT, CONTROL_TYPE_ENUM.WIDTH, CONTROL_TYPE_ENUM.HEIGHT],
|
||||||
|
style: { left: '-5px', bottom: '-5px', cursor: 'nesw-resize' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: '左侧中间',
|
||||||
|
types: [CONTROL_TYPE_ENUM.LEFT, CONTROL_TYPE_ENUM.WIDTH],
|
||||||
|
style: { left: '-5px', top: '50%', cursor: 'w-resize', transform: 'translateX(-50%)' }
|
||||||
|
}
|
||||||
|
] as ControlDot[]
|
||||||
|
|
||||||
|
//region 热区的缩放
|
||||||
|
// 热区的缩放比例
|
||||||
|
export const HOT_ZONE_SCALE_RATE = 2
|
||||||
|
// 缩小:缩回适合手机屏幕的大小
|
||||||
|
export const zoomOut = (list?: HotZoneItemProperty[]) => {
|
||||||
|
return (
|
||||||
|
list?.map((hotZone) => ({
|
||||||
|
...hotZone,
|
||||||
|
left: (hotZone.left /= HOT_ZONE_SCALE_RATE),
|
||||||
|
top: (hotZone.top /= HOT_ZONE_SCALE_RATE),
|
||||||
|
width: (hotZone.width /= HOT_ZONE_SCALE_RATE),
|
||||||
|
height: (hotZone.height /= HOT_ZONE_SCALE_RATE)
|
||||||
|
})) || []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// 放大:作用是为了方便在电脑屏幕上编辑
|
||||||
|
export const zoomIn = (list?: HotZoneItemProperty[]) => {
|
||||||
|
return (
|
||||||
|
list?.map((hotZone) => ({
|
||||||
|
...hotZone,
|
||||||
|
left: (hotZone.left *= HOT_ZONE_SCALE_RATE),
|
||||||
|
top: (hotZone.top *= HOT_ZONE_SCALE_RATE),
|
||||||
|
width: (hotZone.width *= HOT_ZONE_SCALE_RATE),
|
||||||
|
height: (hotZone.height *= HOT_ZONE_SCALE_RATE)
|
||||||
|
})) || []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 封装热区拖拽
|
||||||
|
*
|
||||||
|
* 注:为什么不使用vueuse的useDraggable。在本场景下,其使用方式比较复杂
|
||||||
|
* @param hotZone 热区
|
||||||
|
* @param downEvent 鼠标按下事件
|
||||||
|
* @param callback 回调函数
|
||||||
|
*/
|
||||||
|
export const useDraggable = (
|
||||||
|
hotZone: HotZoneItemProperty,
|
||||||
|
downEvent: MouseEvent,
|
||||||
|
callback: (
|
||||||
|
left: number,
|
||||||
|
top: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
moveWidth: number,
|
||||||
|
moveHeight: number
|
||||||
|
) => void
|
||||||
|
) => {
|
||||||
|
// 阻止事件冒泡
|
||||||
|
downEvent.stopPropagation()
|
||||||
|
|
||||||
|
// 移动前的鼠标坐标
|
||||||
|
const { clientX: startX, clientY: startY } = downEvent
|
||||||
|
// 移动前的热区坐标、大小
|
||||||
|
const { left, top, width, height } = hotZone
|
||||||
|
|
||||||
|
// 监听鼠标移动
|
||||||
|
document.onmousemove = (e) => {
|
||||||
|
// 移动宽度
|
||||||
|
const moveWidth = e.clientX - startX
|
||||||
|
// 移动高度
|
||||||
|
const moveHeight = e.clientY - startY
|
||||||
|
// 移动回调
|
||||||
|
callback(left, top, width, height, moveWidth, moveHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 松开鼠标后,结束拖拽
|
||||||
|
document.onmouseup = () => {
|
||||||
|
document.onmousemove = null
|
||||||
|
document.onmouseup = null
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,236 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog v-model="dialogVisible" title="设置热区" width="780" @close="handleClose">
|
||||||
|
<div ref="container" class="relative h-full w-750px">
|
||||||
|
<el-image :src="imgUrl" class="pointer-events-none h-full w-750px select-none" />
|
||||||
|
<div
|
||||||
|
v-for="(item, hotZoneIndex) in formData"
|
||||||
|
:key="hotZoneIndex"
|
||||||
|
class="hot-zone"
|
||||||
|
:style="{
|
||||||
|
width: `${item.width}px`,
|
||||||
|
height: `${item.height}px`,
|
||||||
|
top: `${item.top}px`,
|
||||||
|
left: `${item.left}px`
|
||||||
|
}"
|
||||||
|
@mousedown="handleMove(item, $event)"
|
||||||
|
@dblclick="handleShowAppLinkDialog(item)"
|
||||||
|
>
|
||||||
|
<span class="pointer-events-none select-none">{{ item.name || '双击选择链接' }}</span>
|
||||||
|
<Icon icon="ep:close" class="delete" :size="14" @click="handleRemove(item)" />
|
||||||
|
|
||||||
|
<!-- 8个控制点 -->
|
||||||
|
<span
|
||||||
|
class="ctrl-dot"
|
||||||
|
v-for="(dot, dotIndex) in CONTROL_DOT_LIST"
|
||||||
|
:key="dotIndex"
|
||||||
|
:style="dot.style"
|
||||||
|
@mousedown="handleResize(item, dot, $event)"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="handleAdd" type="primary" plain>
|
||||||
|
<Icon icon="ep:plus" class="mr-5px" />
|
||||||
|
添加热区
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="handleSubmit" type="primary" plain>
|
||||||
|
<Icon icon="ep:check" class="mr-5px" />
|
||||||
|
确定
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
<AppLinkSelectDialog ref="appLinkDialogRef" @app-link-change="handleAppLinkChange" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { HotZoneItemProperty } from '@/components/DiyEditor/components/mobile/HotZone/config'
|
||||||
|
import { array, string } from 'vue-types'
|
||||||
|
import {
|
||||||
|
CONTROL_DOT_LIST,
|
||||||
|
CONTROL_TYPE_ENUM,
|
||||||
|
ControlDot,
|
||||||
|
HOT_ZONE_MIN_SIZE,
|
||||||
|
useDraggable,
|
||||||
|
zoomIn,
|
||||||
|
zoomOut
|
||||||
|
} from './controller'
|
||||||
|
import { AppLink } from '@/components/AppLinkInput/data'
|
||||||
|
import { remove } from 'lodash-es'
|
||||||
|
|
||||||
|
/** 热区编辑对话框 */
|
||||||
|
defineOptions({ name: 'HotZoneEditDialog' })
|
||||||
|
|
||||||
|
// 定义属性
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: array<HotZoneItemProperty>(),
|
||||||
|
imgUrl: string().def('')
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const formData = ref<HotZoneItemProperty[]>([])
|
||||||
|
|
||||||
|
// 弹窗的是否显示
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
// 打开弹窗
|
||||||
|
const open = () => {
|
||||||
|
// 放大
|
||||||
|
formData.value = zoomIn(props.modelValue)
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
// 提供 open 方法,用于打开弹窗
|
||||||
|
defineExpose({ open })
|
||||||
|
|
||||||
|
// 热区容器
|
||||||
|
const container = ref<HTMLDivElement>()
|
||||||
|
|
||||||
|
// 增加热区
|
||||||
|
const handleAdd = () => {
|
||||||
|
formData.value.push({
|
||||||
|
width: HOT_ZONE_MIN_SIZE,
|
||||||
|
height: HOT_ZONE_MIN_SIZE,
|
||||||
|
top: 0,
|
||||||
|
left: 0
|
||||||
|
} as HotZoneItemProperty)
|
||||||
|
}
|
||||||
|
// 删除热区
|
||||||
|
const handleRemove = (hotZone: HotZoneItemProperty) => {
|
||||||
|
remove(formData.value, hotZone)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动热区
|
||||||
|
const handleMove = (item: HotZoneItemProperty, e: MouseEvent) => {
|
||||||
|
useDraggable(item, e, (left, top, _, __, moveWidth, moveHeight) => {
|
||||||
|
setLeft(item, left + moveWidth)
|
||||||
|
setTop(item, top + moveHeight)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调整热区大小、位置
|
||||||
|
const handleResize = (item: HotZoneItemProperty, ctrlDot: ControlDot, e: MouseEvent) => {
|
||||||
|
useDraggable(item, e, (left, top, width, height, moveWidth, moveHeight) => {
|
||||||
|
ctrlDot.types.forEach((type) => {
|
||||||
|
switch (type) {
|
||||||
|
case CONTROL_TYPE_ENUM.LEFT:
|
||||||
|
setLeft(item, left + moveWidth)
|
||||||
|
break
|
||||||
|
case CONTROL_TYPE_ENUM.TOP:
|
||||||
|
setTop(item, top + moveHeight)
|
||||||
|
break
|
||||||
|
case CONTROL_TYPE_ENUM.WIDTH:
|
||||||
|
{
|
||||||
|
// 上移时,高度为减少
|
||||||
|
const direction = ctrlDot.types.includes(CONTROL_TYPE_ENUM.LEFT) ? -1 : 1
|
||||||
|
setWidth(item, width + moveWidth * direction)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case CONTROL_TYPE_ENUM.HEIGHT:
|
||||||
|
{
|
||||||
|
// 左移时,宽度为减少
|
||||||
|
const direction = ctrlDot.types.includes(CONTROL_TYPE_ENUM.TOP) ? -1 : 1
|
||||||
|
setHeight(item, height + moveHeight * direction)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置X轴坐标
|
||||||
|
const setLeft = (item: HotZoneItemProperty, left: number) => {
|
||||||
|
// 不能超出容器
|
||||||
|
if (left >= 0 && left <= container.value!.offsetWidth - item.width) {
|
||||||
|
item.left = left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置Y轴坐标
|
||||||
|
const setTop = (item: HotZoneItemProperty, top: number) => {
|
||||||
|
// 不能超出容器
|
||||||
|
if (top >= 0 && top <= container.value!.offsetHeight - item.height) {
|
||||||
|
item.top = top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置宽度
|
||||||
|
const setWidth = (item: HotZoneItemProperty, width: number) => {
|
||||||
|
// 不能小于最小宽度 && 不能超出容器右边
|
||||||
|
if (width >= HOT_ZONE_MIN_SIZE && item.left + width <= container.value!.offsetWidth) {
|
||||||
|
item.width = width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置高度
|
||||||
|
const setHeight = (item: HotZoneItemProperty, height: number) => {
|
||||||
|
// 不能小于最小高度 && 不能超出容器底部
|
||||||
|
if (height >= HOT_ZONE_MIN_SIZE && item.top + height <= container.value!.offsetHeight) {
|
||||||
|
item.height = height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理对话框关闭
|
||||||
|
const handleSubmit = () => {
|
||||||
|
// 会自动触发handleClose
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理对话框关闭
|
||||||
|
const handleClose = () => {
|
||||||
|
// 缩小
|
||||||
|
const list = zoomOut(formData.value)
|
||||||
|
emit('update:modelValue', list)
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeHotZone = ref<HotZoneItemProperty>()
|
||||||
|
const appLinkDialogRef = ref()
|
||||||
|
const handleShowAppLinkDialog = (hotZone: HotZoneItemProperty) => {
|
||||||
|
activeHotZone.value = hotZone
|
||||||
|
appLinkDialogRef.value.open(hotZone.url)
|
||||||
|
}
|
||||||
|
const handleAppLinkChange = (appLink: AppLink) => {
|
||||||
|
if (!appLink || !activeHotZone.value) return
|
||||||
|
activeHotZone.value.name = appLink.name
|
||||||
|
activeHotZone.value.url = appLink.path
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.hot-zone {
|
||||||
|
position: absolute;
|
||||||
|
background: var(--el-color-primary-light-7);
|
||||||
|
opacity: 0.8;
|
||||||
|
border: 1px solid var(--el-color-primary);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
font-size: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: move;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
/* 控制点 */
|
||||||
|
.ctrl-dot {
|
||||||
|
position: absolute;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: inherit;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 2px 2px 6px 6px;
|
||||||
|
background-color: var(--el-color-primary);
|
||||||
|
border-radius: 0 0 0 80%;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #fff;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.delete {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
42
src/components/DiyEditor/components/mobile/HotZone/config.ts
Normal file
42
src/components/DiyEditor/components/mobile/HotZone/config.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 热区属性 */
|
||||||
|
export interface HotZoneProperty {
|
||||||
|
// 图片地址
|
||||||
|
imgUrl: string
|
||||||
|
// 导航菜单列表
|
||||||
|
list: HotZoneItemProperty[]
|
||||||
|
// 组件样式
|
||||||
|
style: ComponentStyle
|
||||||
|
}
|
||||||
|
/** 热区项目属性 */
|
||||||
|
export interface HotZoneItemProperty {
|
||||||
|
// 链接的名称
|
||||||
|
name: string
|
||||||
|
// 链接
|
||||||
|
url: string
|
||||||
|
// 宽
|
||||||
|
width: number
|
||||||
|
// 高
|
||||||
|
height: number
|
||||||
|
// 上
|
||||||
|
top: number
|
||||||
|
// 左
|
||||||
|
left: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'HotZone',
|
||||||
|
name: '热区',
|
||||||
|
icon: 'tabler:hand-click',
|
||||||
|
property: {
|
||||||
|
imgUrl: '',
|
||||||
|
list: [] as HotZoneItemProperty[],
|
||||||
|
style: {
|
||||||
|
bgType: 'color',
|
||||||
|
bgColor: '#fff',
|
||||||
|
marginBottom: 8
|
||||||
|
} as ComponentStyle
|
||||||
|
}
|
||||||
|
} as DiyComponent<HotZoneProperty>
|
42
src/components/DiyEditor/components/mobile/HotZone/index.vue
Normal file
42
src/components/DiyEditor/components/mobile/HotZone/index.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div class="relative h-full min-h-30px w-full">
|
||||||
|
<el-image :src="property.imgUrl" class="pointer-events-none h-full w-full select-none" />
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in property.list"
|
||||||
|
:key="index"
|
||||||
|
class="hot-zone"
|
||||||
|
:style="{
|
||||||
|
width: `${item.width}px`,
|
||||||
|
height: `${item.height}px`,
|
||||||
|
top: `${item.top}px`,
|
||||||
|
left: `${item.left}px`
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { HotZoneProperty } from './config'
|
||||||
|
|
||||||
|
/** 热区 */
|
||||||
|
defineOptions({ name: 'HotZone' })
|
||||||
|
const props = defineProps<{ property: HotZoneProperty }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.hot-zone {
|
||||||
|
position: absolute;
|
||||||
|
background: var(--el-color-primary-light-7);
|
||||||
|
opacity: 0.8;
|
||||||
|
border: 1px solid var(--el-color-primary);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: move;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<ComponentContainerProperty v-model="formData.style">
|
||||||
|
<!-- 表单 -->
|
||||||
|
<el-form label-width="80px" :model="formData" class="m-t-8px">
|
||||||
|
<el-form-item label="上传图片" prop="imgUrl">
|
||||||
|
<UploadImg v-model="formData.imgUrl" height="50px" width="auto" class="min-w-80px">
|
||||||
|
<template #tip>
|
||||||
|
<el-text type="info" size="small"> 推荐宽度 750</el-text>
|
||||||
|
</template>
|
||||||
|
</UploadImg>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-button type="primary" plain class="w-full" @click="handleOpenEditDialog">
|
||||||
|
设置热区
|
||||||
|
</el-button>
|
||||||
|
</ComponentContainerProperty>
|
||||||
|
<!-- 热区编辑对话框 -->
|
||||||
|
<HotZoneEditDialog ref="editDialogRef" v-model="formData.list" :img-url="formData.imgUrl" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { usePropertyForm } from '@/components/DiyEditor/util'
|
||||||
|
import { HotZoneProperty } from '@/components/DiyEditor/components/mobile/HotZone/config'
|
||||||
|
import HotZoneEditDialog from './components/HotZoneEditDialog/index.vue'
|
||||||
|
|
||||||
|
/** 热区属性面板 */
|
||||||
|
defineOptions({ name: 'HotZoneProperty' })
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: HotZoneProperty }>()
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||||
|
|
||||||
|
// 热区编辑对话框
|
||||||
|
const editDialogRef = ref()
|
||||||
|
// 打开热区编辑对话框
|
||||||
|
const handleOpenEditDialog = () => {
|
||||||
|
editDialogRef.value.open()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.hot-zone {
|
||||||
|
position: absolute;
|
||||||
|
background: #409effbf;
|
||||||
|
border: 1px solid var(--el-color-primary);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: move;
|
||||||
|
|
||||||
|
/* 控制点 */
|
||||||
|
.ctrl-dot {
|
||||||
|
position: absolute;
|
||||||
|
width: 4px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -28,7 +28,7 @@
|
|||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<span
|
<span
|
||||||
v-if="property.layout === 'iconText'"
|
v-if="property.layout === 'iconText'"
|
||||||
class="text-14px"
|
class="text-12px"
|
||||||
:style="{
|
:style="{
|
||||||
color: item.titleColor,
|
color: item.titleColor,
|
||||||
height: `${TITLE_HEIGHT}px`,
|
height: `${TITLE_HEIGHT}px`,
|
||||||
@ -51,7 +51,7 @@ const props = defineProps<{ property: MenuSwiperProperty }>()
|
|||||||
// 标题的高度
|
// 标题的高度
|
||||||
const TITLE_HEIGHT = 20
|
const TITLE_HEIGHT = 20
|
||||||
// 图标的高度
|
// 图标的高度
|
||||||
const ICON_SIZE = 50
|
const ICON_SIZE = 42
|
||||||
// 垂直间距:一行上下的间距
|
// 垂直间距:一行上下的间距
|
||||||
const SPACE_Y = 16
|
const SPACE_Y = 16
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-card header="菜单设置" class="property-group" shadow="never">
|
<el-card header="菜单设置" class="property-group" shadow="never">
|
||||||
<Draggable v-model="formData.list" :empty-item="cloneDeep(EMPTY_MENU_SWIPER_ITEM_PROPERTY">
|
<Draggable v-model="formData.list" :empty-item="cloneDeep(EMPTY_MENU_SWIPER_ITEM_PROPERTY)">
|
||||||
<template #default="{ element }">
|
<template #default="{ element }">
|
||||||
<el-form-item label="图标" prop="iconUrl">
|
<el-form-item label="图标" prop="iconUrl">
|
||||||
<UploadImg v-model="element.iconUrl" height="80px" width="80px">
|
<UploadImg v-model="element.iconUrl" height="80px" width="80px">
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { DiyComponent } from '@/components/DiyEditor/util'
|
import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
/** 标题栏属性 */
|
/** 标题栏属性 */
|
||||||
export interface TitleBarProperty {
|
export interface TitleBarProperty {
|
||||||
|
// 背景图
|
||||||
|
bgImgUrl: string
|
||||||
|
// 偏移
|
||||||
|
marginLeft: number
|
||||||
|
// 显示位置
|
||||||
|
textAlign: 'left' | 'center'
|
||||||
// 主标题
|
// 主标题
|
||||||
title: string
|
title: string
|
||||||
// 副标题
|
// 副标题
|
||||||
@ -12,18 +18,12 @@ export interface TitleBarProperty {
|
|||||||
descriptionSize: number
|
descriptionSize: number
|
||||||
// 标题粗细
|
// 标题粗细
|
||||||
titleWeight: number
|
titleWeight: number
|
||||||
// 显示位置
|
|
||||||
position: 'left' | 'center'
|
|
||||||
// 描述粗细
|
// 描述粗细
|
||||||
descriptionWeight: number
|
descriptionWeight: number
|
||||||
// 标题颜色
|
// 标题颜色
|
||||||
titleColor: string
|
titleColor: string
|
||||||
// 描述颜色
|
// 描述颜色
|
||||||
descriptionColor: string
|
descriptionColor: string
|
||||||
// 背景颜色
|
|
||||||
backgroundColor: string
|
|
||||||
// 底部分割线
|
|
||||||
showBottomBorder: false
|
|
||||||
// 查看更多
|
// 查看更多
|
||||||
more: {
|
more: {
|
||||||
// 是否显示查看更多
|
// 是否显示查看更多
|
||||||
@ -35,6 +35,8 @@ export interface TitleBarProperty {
|
|||||||
// 链接
|
// 链接
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
|
// 组件样式
|
||||||
|
style: ComponentStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义组件
|
// 定义组件
|
||||||
@ -48,18 +50,20 @@ export const component = {
|
|||||||
titleSize: 16,
|
titleSize: 16,
|
||||||
descriptionSize: 12,
|
descriptionSize: 12,
|
||||||
titleWeight: 400,
|
titleWeight: 400,
|
||||||
position: 'left',
|
textAlign: 'left',
|
||||||
descriptionWeight: 200,
|
descriptionWeight: 200,
|
||||||
titleColor: 'rgba(50, 50, 51, 10)',
|
titleColor: 'rgba(50, 50, 51, 10)',
|
||||||
descriptionColor: 'rgba(150, 151, 153, 10)',
|
descriptionColor: 'rgba(150, 151, 153, 10)',
|
||||||
backgroundColor: 'rgba(255, 255, 255, 10)',
|
|
||||||
showBottomBorder: false,
|
|
||||||
more: {
|
more: {
|
||||||
//查看更多
|
//查看更多
|
||||||
show: false,
|
show: false,
|
||||||
type: 'icon',
|
type: 'icon',
|
||||||
text: '查看更多',
|
text: '查看更多',
|
||||||
url: ''
|
url: ''
|
||||||
}
|
},
|
||||||
|
style: {
|
||||||
|
bgType: 'color',
|
||||||
|
bgColor: '#fff'
|
||||||
|
} as ComponentStyle
|
||||||
}
|
}
|
||||||
} as DiyComponent<TitleBarProperty>
|
} as DiyComponent<TitleBarProperty>
|
||||||
|
@ -1,19 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="title-bar">
|
||||||
class="title-bar"
|
<el-image v-if="property.bgImgUrl" :src="property.bgImgUrl" fit="cover" class="w-full" />
|
||||||
:style="{
|
<div class="absolute left-0 top-0 w-full">
|
||||||
background: property.backgroundColor,
|
|
||||||
borderBottom: property.showBottomBorder ? '1px solid #F9F9F9' : '1px solid #fff'
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<div
|
<div
|
||||||
:style="{
|
:style="{
|
||||||
fontSize: `${property.titleSize}px`,
|
fontSize: `${property.titleSize}px`,
|
||||||
fontWeight: property.titleWeight,
|
fontWeight: property.titleWeight,
|
||||||
color: property.titleColor,
|
color: property.titleColor,
|
||||||
textAlign: property.position
|
textAlign: property.textAlign
|
||||||
}"
|
}"
|
||||||
v-if="property.title"
|
v-if="property.title"
|
||||||
>
|
>
|
||||||
@ -25,7 +20,7 @@
|
|||||||
fontSize: `${property.descriptionSize}px`,
|
fontSize: `${property.descriptionSize}px`,
|
||||||
fontWeight: property.descriptionWeight,
|
fontWeight: property.descriptionWeight,
|
||||||
color: property.descriptionColor,
|
color: property.descriptionColor,
|
||||||
textAlign: property.position
|
textAlign: property.textAlign
|
||||||
}"
|
}"
|
||||||
class="m-t-8px"
|
class="m-t-8px"
|
||||||
v-if="property.description"
|
v-if="property.description"
|
||||||
@ -38,10 +33,10 @@
|
|||||||
class="more"
|
class="more"
|
||||||
v-show="property.more.show"
|
v-show="property.more.show"
|
||||||
:style="{
|
:style="{
|
||||||
color: property.more.type === 'text' ? '#38f' : ''
|
color: property.descriptionColor
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ property.more.type === 'icon' ? '' : property.more.text }}
|
<span v-if="property.more.type !== 'icon'"> {{ property.more.text }} </span>
|
||||||
<Icon icon="ep:arrow-right" v-if="property.more.type !== 'text'" />
|
<Icon icon="ep:arrow-right" v-if="property.more.type !== 'text'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -59,8 +54,6 @@ defineProps<{ property: TitleBarProperty }>()
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 20px;
|
min-height: 20px;
|
||||||
padding: 8px 16px;
|
|
||||||
border: 2px solid #fff;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
/* 更多 */
|
/* 更多 */
|
||||||
|
@ -1,25 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="title-bar">
|
<ComponentContainerProperty v-model="formData.style">
|
||||||
<el-form label-width="85px" :model="formData" :rules="rules">
|
<el-form label-width="85px" :model="formData" :rules="rules">
|
||||||
<el-form-item label="主标题" prop="title">
|
<el-card header="风格" class="property-group" shadow="never">
|
||||||
<el-input
|
<el-form-item label="背景图片" prop="bgImgUrl">
|
||||||
v-model="formData.title"
|
<UploadImg v-model="formData.bgImgUrl" width="100%" height="40px">
|
||||||
placeholder="请输入主标题"
|
<template #tip>建议尺寸 750*80</template>
|
||||||
show-word-limit
|
</UploadImg>
|
||||||
maxlength="20"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="副标题" prop="description">
|
<el-form-item label="标题位置" prop="textAlign">
|
||||||
<el-input
|
<el-radio-group v-model="formData!.textAlign">
|
||||||
type="textarea"
|
|
||||||
v-model="formData.description"
|
|
||||||
placeholder="请输入副标题"
|
|
||||||
maxlength="50"
|
|
||||||
show-word-limit
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="显示位置" prop="position">
|
|
||||||
<el-radio-group v-model="formData!.position">
|
|
||||||
<el-tooltip content="居左" placement="top">
|
<el-tooltip content="居左" placement="top">
|
||||||
<el-radio-button label="left">
|
<el-radio-button label="left">
|
||||||
<Icon icon="ant-design:align-left-outlined" />
|
<Icon icon="ant-design:align-left-outlined" />
|
||||||
@ -32,19 +21,26 @@
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标题大小" prop="titleSize">
|
</el-card>
|
||||||
<el-slider v-model="formData.titleSize" :max="60" :min="10" show-input input-size="small" />
|
<el-card header="主标题" class="property-group" shadow="never">
|
||||||
|
<el-form-item label="文字" prop="title" label-width="40px">
|
||||||
|
<InputWithColor
|
||||||
|
v-model="formData.title"
|
||||||
|
v-model:color="formData.titleColor"
|
||||||
|
show-word-limit
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="副标题大小" prop="descriptionSize">
|
<el-form-item label="大小" prop="titleSize" label-width="40px">
|
||||||
<el-slider
|
<el-slider
|
||||||
v-model="formData.descriptionSize"
|
v-model="formData.titleSize"
|
||||||
:max="60"
|
:max="60"
|
||||||
:min="10"
|
:min="10"
|
||||||
show-input
|
show-input
|
||||||
input-size="small"
|
input-size="small"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标题粗细" prop="titleWeight">
|
<el-form-item label="粗细" prop="titleWeight" label-width="40px">
|
||||||
<el-slider
|
<el-slider
|
||||||
v-model="formData.titleWeight"
|
v-model="formData.titleWeight"
|
||||||
:min="100"
|
:min="100"
|
||||||
@ -54,7 +50,26 @@
|
|||||||
input-size="small"
|
input-size="small"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="副标题粗细" prop="descriptionWeight">
|
</el-card>
|
||||||
|
<el-card header="副标题" class="property-group" shadow="never">
|
||||||
|
<el-form-item label="文字" prop="description" label-width="40px">
|
||||||
|
<InputWithColor
|
||||||
|
v-model="formData.description"
|
||||||
|
v-model:color="formData.descriptionColor"
|
||||||
|
show-word-limit
|
||||||
|
maxlength="50"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="大小" prop="descriptionSize" label-width="40px">
|
||||||
|
<el-slider
|
||||||
|
v-model="formData.descriptionSize"
|
||||||
|
:max="60"
|
||||||
|
:min="10"
|
||||||
|
show-input
|
||||||
|
input-size="small"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="粗细" prop="descriptionWeight" label-width="40px">
|
||||||
<el-slider
|
<el-slider
|
||||||
v-model="formData.descriptionWeight"
|
v-model="formData.descriptionWeight"
|
||||||
:min="100"
|
:min="100"
|
||||||
@ -64,22 +79,12 @@
|
|||||||
input-size="small"
|
input-size="small"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标题颜色" prop="titleColor">
|
</el-card>
|
||||||
<ColorInput v-model="formData.titleColor" />
|
<el-card header="查看更多" class="property-group" shadow="never">
|
||||||
</el-form-item>
|
<el-form-item label="是否显示" prop="more.show">
|
||||||
<el-form-item label="副标题颜色" prop="descriptionColor">
|
|
||||||
<ColorInput v-model="formData.descriptionColor" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="背景颜色" prop="backgroundColor">
|
|
||||||
<ColorInput v-model="formData.backgroundColor" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="底部分割线" prop="showBottomBorder">
|
|
||||||
<el-switch v-model="formData!.showBottomBorder" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="查看更多" prop="more.show">
|
|
||||||
<el-checkbox v-model="formData.more.show" />
|
<el-checkbox v-model="formData.more.show" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 更多样式选择 -->
|
<!-- 更多按钮的 样式选择 -->
|
||||||
<template v-if="formData.more.show">
|
<template v-if="formData.more.show">
|
||||||
<el-form-item label="样式" prop="more.type">
|
<el-form-item label="样式" prop="more.type">
|
||||||
<el-radio-group v-model="formData.more.type">
|
<el-radio-group v-model="formData.more.type">
|
||||||
@ -95,8 +100,9 @@
|
|||||||
<AppLinkInput v-model="formData.more.url" />
|
<AppLinkInput v-model="formData.more.url" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
</el-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
</section>
|
</ComponentContainerProperty>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { TitleBarProperty } from './config'
|
import { TitleBarProperty } from './config'
|
||||||
|
@ -124,7 +124,15 @@ export const PAGE_LIBS = [
|
|||||||
{
|
{
|
||||||
name: '图文组件',
|
name: '图文组件',
|
||||||
extended: true,
|
extended: true,
|
||||||
components: ['ImageBar', 'Carousel', 'TitleBar', 'VideoPlayer', 'Divider', 'MagicCube']
|
components: [
|
||||||
|
'ImageBar',
|
||||||
|
'Carousel',
|
||||||
|
'TitleBar',
|
||||||
|
'VideoPlayer',
|
||||||
|
'Divider',
|
||||||
|
'MagicCube',
|
||||||
|
'HotZone'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{ name: '商品组件', extended: true, components: ['ProductCard', 'ProductList'] },
|
{ name: '商品组件', extended: true, components: ['ProductCard', 'ProductList'] },
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user