营销:适配商城装修组件【广告魔方】

This commit is contained in:
owen
2023-11-12 19:29:24 +08:00
parent 55b477acdb
commit 49ebadd748
9 changed files with 548 additions and 3 deletions

View File

@ -135,8 +135,11 @@ $toolbar-position: -55px;
position: relative;
z-index: 1;
}
/* 用于包裹组件,为组件提供 组件名称、工具栏、边框等样式 */
.component-wrap {
z-index: 0;
// 不可以被点击
// component-wrap会遮挡组件导致组件不能触发鼠标事件所以这里要先禁用然后在组件名称、工具栏上开启。
pointer-events: none;
display: block;
position: absolute;
@ -146,6 +149,8 @@ $toolbar-position: -55px;
height: 100%;
/* 左侧:组件名称 */
.component-name {
// 可以被点击
pointer-events: auto;
display: block;
position: absolute;
width: 80px;
@ -174,6 +179,8 @@ $toolbar-position: -55px;
}
/* 右侧:组件操作工具栏 */
.component-toolbar {
// 可以被点击
pointer-events: auto;
display: none;
position: absolute;
top: 0;

View File

@ -21,7 +21,7 @@
</el-carousel>
<div
v-if="property.indicator === 'number'"
class="absolute p-y-2px bottom-10px right-10px rounded-xl bg-black p-x-8px text-10px text-white opacity-40"
class="absolute bottom-10px right-10px rounded-xl bg-black p-x-8px p-y-2px text-10px text-white opacity-40"
>{{ currentIndex }} / {{ property.items.length }}</div
>
</div>

View File

@ -0,0 +1,48 @@
import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
/** 广告魔方属性 */
export interface MagicCubeProperty {
// 上圆角
borderRadiusTop: number
// 下圆角
borderRadiusBottom: number
// 间隔
space: number
// 导航菜单列表
list: MagicCubeItemProperty[]
// 组件样式
style: ComponentStyle
}
/** 广告魔方项目属性 */
export interface MagicCubeItemProperty {
// 图标链接
imgUrl: string
// 链接
url: string
// 宽
width: number
// 高
height: number
// 上
top: number
// 左
left: number
}
// 定义组件
export const component = {
id: 'MagicCube',
name: '广告魔方',
icon: 'fluent:puzzle-cube-piece-20-filled',
property: {
borderRadiusTop: 0,
borderRadiusBottom: 0,
space: 0,
list: [],
style: {
bgType: 'color',
bgColor: '#fff',
marginBottom: 8
} as ComponentStyle
}
} as DiyComponent<MagicCubeProperty>

View File

@ -0,0 +1,73 @@
<template>
<div
class="relative"
:style="{ height: `${rowCount * CUBE_SIZE}px`, width: `${4 * CUBE_SIZE}px` }"
>
<div
v-for="(item, index) in property.list"
:key="index"
class="absolute"
:style="{
width: `${item.width * CUBE_SIZE - property.space * 2}px`,
height: `${item.height * CUBE_SIZE - property.space * 2}px`,
margin: `${property.space}px`,
top: `${item.top * CUBE_SIZE}px`,
left: `${item.left * CUBE_SIZE}px`
}"
>
<el-image
class="h-full w-full"
fit="cover"
:src="item.imgUrl"
:style="{
borderTopLeftRadius: `${property.borderRadiusTop}px`,
borderTopRightRadius: `${property.borderRadiusTop}px`,
borderBottomLeftRadius: `${property.borderRadiusBottom}px`,
borderBottomRightRadius: `${property.borderRadiusBottom}px`
}"
>
<template #error>
<div class="image-slot">
<div
class="flex items-center justify-center"
:style="{
width: `${item.width * CUBE_SIZE}px`,
height: `${item.height * CUBE_SIZE}px`
}"
>
<Icon icon="ep-picture" color="gray" :size="CUBE_SIZE" />
</div>
</div>
</template>
</el-image>
</div>
</div>
</template>
<script setup lang="ts">
import { MagicCubeProperty } from './config'
/** 广告魔方 */
defineOptions({ name: 'MagicCube' })
const props = defineProps<{ property: MagicCubeProperty }>()
// 一个方块的大小
const CUBE_SIZE = 93.75
/**
* 计算方块的行数
* 行数用于计算魔方的总体高度,存在以下情况:
* 1. 没有数据时,默认就只显示一行的高度
* 2. 底部的空白不算高度,例如只有第一行有数据,那么就只显示一行的高度
* 3. 顶部及中间的空白算高度,例如一共有四行,只有最后一行有数据,那么也显示四行的高度
*/
const rowCount = computed(() => {
let count = 0
if (props.property.list.length > 0) {
// 最大行号
count = Math.max(...props.property.list.map((item) => item.bottom))
}
// 行号从 0 开始,所以加 1
return count + 1
})
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,76 @@
<template>
<ComponentContainerProperty v-model="formData.style">
<!-- 表单 -->
<el-form label-width="80px" :model="formData" class="m-t-8px">
<el-text tag="p"> 魔方设置 </el-text>
<el-text type="info" size="small"> 每格尺寸187 * 187 </el-text>
<MagicCubeEditor
class="m-y-16px"
v-model="formData.list"
:rows="4"
:cols="4"
@hot-area-selected="handleHotAreaSelected"
/>
<template v-for="(hotArea, index) in formData.list" :key="index">
<template v-if="selectedHotAreaIndex === index">
<el-form-item label="上传图片" :prop="`list[${index}].imgUrl`">
<UploadImg v-model="hotArea.imgUrl" height="80px" width="80px" />
</el-form-item>
<el-form-item label="链接" :prop="`list[${index}].url`">
<el-input v-model="hotArea.url" placeholder="请输入链接" />
</el-form-item>
</template>
</template>
<el-form-item label="上圆角" prop="borderRadiusTop">
<el-slider
v-model="formData.borderRadiusTop"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
<el-form-item label="下圆角" prop="borderRadiusBottom">
<el-slider
v-model="formData.borderRadiusBottom"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
<el-form-item label="间隔" prop="space">
<el-slider
v-model="formData.space"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
</el-form>
</ComponentContainerProperty>
</template>
<script setup lang="ts">
import { usePropertyForm } from '@/components/DiyEditor/util'
import { MagicCubeProperty } from '@/components/DiyEditor/components/mobile/MagicCube/config'
/** 广告魔方属性面板 */
defineOptions({ name: 'MagicCubeProperty' })
const props = defineProps<{ modelValue: MagicCubeProperty }>()
const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit)
// 选中的热区
const selectedHotAreaIndex = ref(-1)
const handleHotAreaSelected = (_: any, index: number) => {
selectedHotAreaIndex.value = index
}
</script>
<style scoped lang="scss"></style>

View File

@ -105,7 +105,7 @@ export const PAGE_LIBS = [
{
name: '图文组件',
extended: true,
components: ['ImageBar', 'Carousel', 'TitleBar', 'VideoPlayer', 'Divider']
components: ['ImageBar', 'Carousel', 'TitleBar', 'VideoPlayer', 'Divider', 'MagicCube']
},
{ name: '商品组件', extended: true, components: ['ProductCard'] },
{