营销:适配商城装修组件【轮播图】
This commit is contained in:
parent
6e9e1d0888
commit
4253173a2a
@ -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>
|
||||||
|
@ -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>
|
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user