营销:适配商城装修组件【弹窗广告】

This commit is contained in:
owen 2023-12-09 16:45:54 +08:00
parent 605f906056
commit 76025b6821
5 changed files with 177 additions and 1 deletions

View File

@ -0,0 +1,26 @@
import { DiyComponent } from '@/components/DiyEditor/util'
/** 弹窗广告属性 */
export interface PopoverProperty {
list: PopoverItemProperty[]
}
export interface PopoverItemProperty {
// 图片地址
imgUrl: string
// 跳转连接
url: string
// 显示类型:仅显示一次、每次启动都会显示
showType: 'once' | 'always'
}
// 定义组件
export const component = {
id: 'Popover',
name: '弹窗广告',
icon: 'carbon:popup',
position: 'fixed',
property: {
list: [{ showType: 'once' }]
}
} as DiyComponent<PopoverProperty>

View File

@ -0,0 +1,38 @@
<template>
<div
v-for="(item, index) in property.list"
:key="index"
class="absolute bottom-50% right-50% h-454px w-292px border-1px border-gray border-rounded-4px border-solid bg-white p-1px"
:style="{
zIndex: 100 + index + (activeIndex === index ? 100 : 0),
marginRight: `${-146 - index * 20}px`,
marginBottom: `${-227 - index * 20}px`
}"
@click="handleActive(index)"
>
<el-image :src="item.imgUrl" fit="contain" class="h-full w-full">
<template #error>
<div class="h-full w-full flex items-center justify-center">
<Icon icon="ep:picture" />
</div>
</template>
</el-image>
<div class="absolute right-1 top-1 text-12px">{{ index + 1 }}</div>
</div>
</template>
<script setup lang="ts">
import { PopoverProperty } from './config'
/** 弹窗广告 */
defineOptions({ name: 'Popover' })
//
defineProps<{ property: PopoverProperty }>()
//
const activeIndex = ref(0)
const handleActive = (index: number) => {
activeIndex.value = index
}
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,38 @@
<template>
<el-form label-width="80px" :model="formData">
<Draggable v-model="formData.list" :empty-item="{ showType: 'once' }">
<template #default="{ element, index }">
<el-form-item label="图片" :prop="`list[${index}].imgUrl`">
<UploadImg v-model="element.imgUrl" height="56px" width="56px" />
</el-form-item>
<el-form-item label="跳转链接" :prop="`list[${index}].url`">
<AppLinkInput v-model="element.url" />
</el-form-item>
<el-form-item label="显示次数" :prop="`list[${index}].showType`">
<el-radio-group v-model="element.showType">
<el-tooltip content="只显示一次,下次打开时不显示" placement="bottom">
<el-radio label="once">一次</el-radio>
</el-tooltip>
<el-tooltip content="每次打开时都会显示" placement="bottom">
<el-radio label="always">不限</el-radio>
</el-tooltip>
</el-radio-group>
</el-form-item>
</template>
</Draggable>
</el-form>
</template>
<script setup lang="ts">
import { PopoverProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util'
// 广
defineOptions({ name: 'PopoverProperty' })
const props = defineProps<{ modelValue: PopoverProperty }>()
const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit)
</script>
<style scoped lang="scss"></style>

View File

@ -47,6 +47,18 @@
class="cursor-pointer!"
/>
</div>
<!-- 绝对定位的组件例如 弹窗浮动按钮等 -->
<div
v-for="(component, index) in pageComponents"
:key="index"
@click="handleComponentSelected(component, index)"
>
<component
v-if="component.position === 'fixed' && selectedComponent?.uid === component.uid"
:is="component.id"
:property="component.property"
/>
</div>
<!-- 手机页面编辑区域 -->
<el-scrollbar
height="100%"
@ -70,6 +82,7 @@
>
<template #item="{ element, index }">
<ComponentContainer
v-if="!element.position || element.position === 'center'"
:component="element"
:active="selectedComponentIndex === index"
:can-move-up="index > 0"
@ -91,6 +104,33 @@
@click="handleTabBarSelected"
/>
</div>
<!-- 固定布局的组件 操作按钮区 -->
<div class="fixed-component-action-group">
<el-tag
v-if="showPageConfig"
size="large"
:effect="selectedComponent?.uid === pageConfigComponent.uid ? 'dark' : 'plain'"
:type="selectedComponent?.uid === pageConfigComponent.uid ? '' : 'info'"
@click="handleComponentSelected(pageConfigComponent)"
>
<Icon :icon="pageConfigComponent.icon" :size="12" />
<span>{{ pageConfigComponent.name }}</span>
</el-tag>
<template v-for="(component, index) in pageComponents" :key="index">
<el-tag
v-if="component.position === 'fixed'"
size="large"
closable
:effect="selectedComponent?.uid === component.uid ? 'dark' : 'plain'"
:type="selectedComponent?.uid === component.uid ? '' : 'info'"
@click="handleComponentSelected(component)"
@close="handleDeleteComponent(index)"
>
<Icon :icon="component.icon" :size="12" />
<span>{{ component.name }}</span>
</el-tag>
</template>
</div>
</div>
<!-- 右侧属性面板 -->
<el-aside class="editor-right" width="350px" v-if="selectedComponent?.property">
@ -485,6 +525,31 @@ $toolbar-height: 42px;
}
}
}
/* 固定布局的组件 操作按钮区 */
.fixed-component-action-group {
position: absolute;
top: 0;
right: 16px;
display: flex;
flex-direction: column;
gap: 8px;
:deep(.el-tag) {
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
border: none;
.el-tag__content {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
.el-icon {
margin-right: 4px;
}
}
}
}
}
}
}

View File

@ -13,6 +13,15 @@ export interface DiyComponent<T> {
name: string
// 组件图标
icon: string
/*
top: 固定于手机顶部
bottom: 固定于手机底部
center: 位于手机中心
center
fixed: 由组件自己决定位置
*/
position: 'top' | 'bottom' | 'center' | '' | 'fixed'
// 组件属性
property: T
}
@ -102,7 +111,7 @@ export const PAGE_LIBS = [
{
name: '基础组件',
extended: true,
components: ['SearchBar', 'NoticeBar', 'MenuSwiper', 'MenuGrid', 'MenuList']
components: ['SearchBar', 'NoticeBar', 'MenuSwiper', 'MenuGrid', 'MenuList', 'Popover']
},
{
name: '图文组件',