营销:适配商城装修组件【轮播图】

This commit is contained in:
owen 2023-11-06 09:31:42 +08:00
parent 6e9e1d0888
commit 4253173a2a
5 changed files with 182 additions and 185 deletions

View File

@ -1,27 +1,30 @@
import { DiyComponent } from '@/components/DiyEditor/util' import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
/** 轮播图属性 */ /** 轮播图属性 */
export interface CarouselProperty { export interface CarouselProperty {
// 选择模板 // 类型:默认 | 卡片
swiperType: number type: 'default' | 'card'
// 图片圆角 // 指示器样式:点 | 数字
borderRadius: number indicator: 'dot' | 'number'
// 页面边距 // 是否自动播放
pageMargin: number autoplay: boolean
// 图片边距 // 播放间隔
imageMargin: number interval: number
// 分页类型 // 轮播内容
pagingType: 'bullets' | 'fraction' | 'progressbar'
// 一行个数
rowIndividual: number
// 添加图片
items: CarouselItemProperty[] items: CarouselItemProperty[]
// 组件样式
style: ComponentStyle
} }
// 轮播内容属性
export interface CarouselItemProperty { export interface CarouselItemProperty {
title: string // 类型:图片 | 视频
type: 'img' | 'video'
// 图片链接
imgUrl: string imgUrl: string
link: string // 视频链接
videoUrl: string
// 跳转链接
url: string
} }
// 定义组件 // 定义组件
@ -30,15 +33,18 @@ export const component = {
name: '轮播图', name: '轮播图',
icon: 'system-uicons:carousel', icon: 'system-uicons:carousel',
property: { property: {
swiperType: 0, // 选择模板 type: 'default',
borderRadius: 0, // 图片圆角 indicator: 'dot',
pageMargin: 0, // 页面边距 autoplay: false,
imageMargin: 0, // 图片边距 interval: 3,
pagingType: 'bullets', // 分页类型
rowIndividual: 2, // 一行个数
items: [ items: [
{ imgUrl: 'https://static.iocoder.cn/mall/banner-01.jpg' }, { type: 'img', imgUrl: 'https://static.iocoder.cn/mall/banner-01.jpg', videoUrl: '' },
{ imgUrl: 'https://static.iocoder.cn/mall/banner-02.jpg' } { type: 'img', imgUrl: 'https://static.iocoder.cn/mall/banner-02.jpg', videoUrl: '' }
] as CarouselItemProperty[] ] as CarouselItemProperty[],
style: {
bgType: 'color',
bgColor: '#fff',
marginBottom: 8
} as ComponentStyle
} }
} as DiyComponent<CarouselProperty> } as DiyComponent<CarouselProperty>

View File

@ -6,70 +6,38 @@
> >
<Icon icon="tdesign:image" class="text-gray-8 text-120px!" /> <Icon icon="tdesign:image" class="text-gray-8 text-120px!" />
</div> </div>
<!-- 一行一个 --> <div v-else class="relative">
<div <el-carousel
v-if="property.swiperType === 0" height="174px"
class="flex flex-col" :type="property.type === 'card' ? 'card' : ''"
:style="{ :autoplay="property.autoplay"
paddingLeft: property.pageMargin + 'px', :interval="property.interval * 1000"
paddingRight: property.pageMargin + 'px' :indicator-position="property.indicator === 'number' ? 'none' : undefined"
}" @change="handleIndexChange"
> >
<div v-for="(item, index) in property.items" :key="index"> <el-carousel-item v-for="(item, index) in property.items" :key="index">
<div <el-image class="h-full w-full" :src="item.imgUrl" />
class="img-item" </el-carousel-item>
:style="{ </el-carousel>
marginBottom: property.imageMargin + 'px', <div
borderRadius: property.borderRadius + 'px' 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"
> >{{ currentIndex }} / {{ property.items.length }}</div
<img alt="" :src="item.imgUrl" /> >
<div v-if="item.title" class="title">{{ item.title }}</div>
</div>
</div>
</div> </div>
<el-carousel height="174px" v-else :type="property.swiperType === 3 ? 'card' : ''">
<el-carousel-item v-for="(item, index) in property.items" :key="index">
<div class="img-item" :style="{ borderRadius: property.borderRadius + 'px' }">
<img alt="" :src="item.imgUrl" />
<div v-if="item.title" class="title">{{ item.title }}</div>
</div>
</el-carousel-item>
</el-carousel>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { CarouselProperty } from './config' import { CarouselProperty } from './config'
/** 页面顶部导航栏 */ /** 轮播图 */
defineOptions({ name: 'NavigationBar' }) defineOptions({ name: 'Carousel' })
const props = defineProps<{ property: CarouselProperty }>() defineProps<{ property: CarouselProperty }>()
const currentIndex = ref(0)
const handleIndexChange = (index: number) => {
currentIndex.value = index + 1
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
.img-item {
width: 100%;
position: relative;
overflow: hidden;
&:last-child {
margin: 0 !important;
}
/* 图片 */
img {
width: 100%;
height: 100%;
display: block;
}
.title {
height: 36px;
width: 100%;
background-color: rgba(51, 51, 51, 0.8);
text-align: center;
line-height: 36px;
color: #fff;
position: absolute;
bottom: 0;
left: 0;
}
}
</style>

View File

@ -1,103 +1,120 @@
<template> <template>
<el-form label-width="80px" :model="formData"> <ComponentContainerProperty v-model="formData.style">
<el-form-item label="选择模板" prop="swiperType"> <el-form label-width="80px" :model="formData">
<el-radio-group v-model="formData.swiperType"> <el-card header="样式设置" class="property-group" shadow="never">
<el-tooltip class="item" content="一行一个" placement="bottom"> <el-form-item label="样式" prop="type">
<el-radio-button :label="0"> <el-radio-group v-model="formData.type">
<Icon icon="icon-park-twotone:multi-picture-carousel" /> <el-tooltip class="item" content="默认" placement="bottom">
</el-radio-button> <el-radio-button label="default">
</el-tooltip> <Icon icon="system-uicons:carousel" />
<el-tooltip class="item" content="轮播海报" placement="bottom"> </el-radio-button>
<el-radio-button :label="1"> </el-tooltip>
<Icon icon="system-uicons:carousel" /> <el-tooltip class="item" content="卡片" placement="bottom">
</el-radio-button> <el-radio-button label="card">
</el-tooltip> <Icon icon="ic:round-view-carousel" />
<el-tooltip class="item" content="多图单行" placement="bottom"> </el-radio-button>
<el-radio-button :label="2"> </el-tooltip>
<Icon icon="icon-park-twotone:carousel" /> </el-radio-group>
</el-radio-button> </el-form-item>
</el-tooltip> <el-form-item label="指示器" prop="indicator">
<el-tooltip class="item" content="立体轮播" placement="bottom"> <el-radio-group v-model="formData.indicator">
<el-radio-button :label="3"> <el-radio label="dot">小圆点</el-radio>
<Icon icon="ic:round-view-carousel" /> <el-radio label="number">数字</el-radio>
</el-radio-button> </el-radio-group>
</el-tooltip> </el-form-item>
</el-radio-group> <el-form-item label="是否轮播" prop="autoplay">
</el-form-item> <el-switch v-model="formData.autoplay" />
</el-form-item>
<el-text tag="p">添加图片</el-text> <el-form-item label="播放间隔" prop="interval" v-if="formData.autoplay">
<el-text type="info" size="small"> 拖动左上角的小圆点可对其排序 </el-text> <el-slider
v-model="formData.interval"
<!-- 图片广告 --> :max="10"
<div v-if="formData.items[0]"> :min="0.5"
<draggable :step="0.5"
:list="formData.items" show-input
:force-fallback="true" input-size="small"
:animation="200" :show-input-controls="false"
handle=".drag-icon" />
class="m-t-8px" <el-text type="info">单位</el-text>
> </el-form-item>
<template #item="{ element, index }"> </el-card>
<div class="mb-4px flex flex-row gap-4px rounded bg-gray-100 p-8px"> <el-card header="内容设置" class="property-group" shadow="never">
<div class="flex flex-col items-start justify-between"> <el-text type="info" size="small"> 拖动左上角的小圆点可对其排序 </el-text>
<Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" /> <template v-if="formData.items[0]">
<Icon <draggable
icon="ep:delete" :list="formData.items"
class="cursor-pointer text-red-5" :force-fallback="true"
@click="handleDeleteImage(index)" :animation="200"
v-if="formData.items.length > 1" handle=".drag-icon"
/> class="m-t-8px"
</div> item-key="index"
<div class="flex flex-1 flex-col items-center justify-between gap-8px"> >
<UploadImg <template #item="{ element, index }">
v-model="element.imgUrl" <div class="content mb-4px flex flex-col gap-4px rounded bg-gray-50 p-8px">
draggable="false" <div
height="80px" class="m--8px m-b-8px flex flex-row items-center justify-between bg-gray-100 p-8px"
width="100%" >
class="min-w-80px" <Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" />
/> <Icon
<!-- 标题 --> icon="ep:delete"
<el-input v-model="element.title" placeholder="标题,选填" /> class="cursor-pointer text-red-5"
<!-- 输入链接 --> @click="handleDeleteImage(index)"
<el-input placeholder="链接,选填" v-model="element.link" /> v-if="formData.items.length > 1"
</div> />
</div> </div>
<el-form-item label="类型" prop="type" class="m-b-8px!" label-width="50px">
<el-radio-group v-model="element.type">
<el-radio label="img">图片</el-radio>
<el-radio label="video">视频</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label="图片"
class="m-b-8px!"
label-width="50px"
v-if="element.type === 'img'"
>
<UploadImg
v-model="element.imgUrl"
draggable="false"
height="80px"
width="100%"
class="min-w-80px"
/>
</el-form-item>
<template v-else>
<el-form-item label="封面" class="m-b-8px!" label-width="50px">
<UploadImg
v-model="element.imgUrl"
draggable="false"
height="80px"
width="100%"
class="min-w-80px"
/>
</el-form-item>
<el-form-item label="视频" class="m-b-8px!" label-width="50px">
<UploadFile
v-model="element.videoUrl"
:file-type="['mp4']"
:limit="1"
:file-size="100"
class="min-w-80px"
/>
</el-form-item>
</template>
<el-form-item label="链接" class="m-b-8px!" label-width="50px">
<el-input placeholder="链接" v-model="element.url" />
</el-form-item>
</div>
</template>
</draggable>
</template> </template>
</draggable> <el-button @click="handleAddImage" type="primary" plain class="w-full">
</div> 添加图片
<el-button @click="handleAddImage" type="primary" plain class="w-full"> 添加图片 </el-button> </el-button>
<el-form-item label="一行个数" prop="rowIndividual" v-show="formData.swiperType === 2"> </el-card>
<!-- 单选框 --> </el-form>
<el-radio-group v-model="formData.rowIndividual"> </ComponentContainerProperty>
<el-radio :label="2">2</el-radio>
<el-radio :label="3">3</el-radio>
<el-radio :label="4">4</el-radio>
<el-radio :label="5">5</el-radio>
<el-radio :label="6">6</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="分页类型" prop="pagingType">
<el-radio-group v-model="formData.pagingType">
<el-radio :label="0">不显示</el-radio>
<el-radio label="bullets">样式一</el-radio>
<el-radio label="fraction">样式二</el-radio>
<el-radio label="progressbar">样式三</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="图片圆角" prop="borderRadius">
<el-slider v-model="formData.borderRadius" :max="30" />
</el-form-item>
<el-form-item label="页面边距" prop="pageMargin" v-show="formData.swiperType === 0">
<el-slider v-model="formData.pageMargin" :max="20" />
</el-form-item>
<el-form-item
label="图片边距"
prop="imageMargin"
v-show="formData.swiperType === 0 || formData.swiperType === 2"
>
<el-slider v-model="formData.imageMargin" :max="20" />
</el-form-item>
</el-form>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -117,7 +134,7 @@ const handleAddImage = () => {
formData.value.items.push({} as CarouselItemProperty) formData.value.items.push({} as CarouselItemProperty)
} }
// //
const handleDeleteImage = (index) => { const handleDeleteImage = (index: number) => {
formData.value.items.splice(index, 1) formData.value.items.splice(index, 1)
} }
</script> </script>

View File

@ -385,12 +385,18 @@ $toolbar-height: 42px;
/* 属性面板分组 */ /* 属性面板分组 */
:deep(.property-group) { :deep(.property-group) {
margin: 0 -20px; margin: 0 -20px;
&.el-card {
border: none;
}
/* 属性分组名称 */ /* 属性分组名称 */
.el-card__header { .el-card__header {
border: none; border: none;
background: var(--el-bg-color-page); background: var(--el-bg-color-page);
padding: 8px 32px; padding: 8px 32px;
} }
.el-card__body {
border: none;
}
} }
} }

View File

@ -138,7 +138,7 @@ watch(
// 1.1 // 1.1
if (props.modelValue.includes(',')) { if (props.modelValue.includes(',')) {
files.concat(props.modelValue.split(',')) files.concat(props.modelValue.split(','))
} else { } else if (props.modelValue.length > 0) {
files.push(props.modelValue) files.push(props.modelValue)
} }
} else if (isArray(props.modelValue)) { } else if (isArray(props.modelValue)) {