修改轮播和选项卡新需求

v1.1.0
于肖磊 2024-12-12 17:14:31 +08:00
parent bce7b5966f
commit acbed6c813
16 changed files with 287 additions and 74 deletions

View File

@ -100,7 +100,7 @@ onBeforeMount(() => {
//
const old_defalut = new_dataInterface.value[item.form_name];
//
if (old_defalut !== '' && old_defalut !== undefined && ['select', 'radio', 'checkout'].includes(item.type)) {
if (old_defalut !== '' && old_defalut != null && ['select', 'radio', 'checkout'].includes(item.type)) {
if (item.type == 'select' && +item?.config?.is_level == 1) { //
const result = contains_value(options_list, item, [], item?.config?.children || '');
new_dataInterface.value[item.form_name] = result;

View File

@ -4,10 +4,10 @@
<template v-for="(item, index) in form.tabs_list" :key="index">
<div class="item nowrap flex-col jc-c" :class="tabs_theme + (index == activeIndex ? ' active' : '') + ((tabs_theme_index == '0' && tabs_theme_1_style) || tabs_theme_index == '1' || tabs_theme_index == '2' ? ' pb-0' : '')" :style="`row-gap: ${new_style.tabs_sign_spacing}px;`">
<template v-if="!isEmpty(item.img)">
<image-empty v-model="item.img[0]" class="img" error-img-style="width:2rem;height:2rem;"></image-empty>
<image-empty v-model="item.img[0]" class="img" :style="top_img_style('data')" fit="contain" error-img-style="width:3.9rem;height:3.9rem;"></image-empty>
</template>
<template v-else>
<image-empty class="img" error-img-style="width:2rem;height:2rem;"></image-empty>
<image-empty class="img" :style="top_img_style('noData')" fit="contain" error-img-style="width:3.9rem;height:3.9rem;"></image-empty>
</template>
<template v-if="item.tabs_type == '1'">
<template v-if="!isEmpty(item.tabs_icon)">
@ -131,6 +131,12 @@ const img_style = () => {
return style;
};
const top_img_style = (type: string) => {
const tabs_top_img_height = new_style.value?.tabs_top_img_height || 39;
const tabs_top_img_radius = new_style.value?.tabs_top_img_radius || { radius: 100, radius_top_left: 100, radius_top_right: 100, radius_bottom_left: 100, radius_bottom_right: 100}
return `height: ${tabs_top_img_height}px; width: ${ type == 'noData' ? tabs_top_img_height + 'px;' : '100%;' }` + radius_computer(tabs_top_img_radius);
};
const padding_bottom = computed(() => {
let bottom = 0;
if (form.value.tabs_theme == '0') {
@ -195,9 +201,9 @@ const icon_tabs_check = () => {
display: none;
}
.img {
width: 3.9rem;
height: 3.9rem;
border-radius: 100%;
// width: 3.9rem;
// height: 3.9rem;
// border-radius: 100%;
border: 0.1rem solid transparent;
display: none;
}

View File

@ -1,6 +1,6 @@
<template>
<div :style="style_container">
<div class="re" :style="style_img_container">
<div :style="style_container + swiper_bg_style">
<div class="re" :style="style_img_container + swiper_bg_img_style">
<div ref="swiperSize" class="swiper-container w h oh">
<swiper
:key="carouselKey"
@ -73,7 +73,7 @@
</div>
</template>
<script setup lang="ts">
import { common_styles_computer, radius_computer, get_math, gradient_computer, padding_computer, common_img_computer } from '@/utils';
import { common_styles_computer, radius_computer, get_math, gradient_computer, padding_computer, common_img_computer, background_computer } from '@/utils';
import { isEmpty, cloneDeep, throttle } from 'lodash';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Autoplay, EffectCoverflow } from 'swiper/modules';
@ -153,7 +153,7 @@ const indicator_location_style = computed(() => {
});
//#endregion
const seat_list = computed(() => {
if (form.value.carousel_list.length > 3) {
if (form.value.carousel_list.length > 3 || form.value.carousel_type !== 'card') {
return [];
} else {
let seat_list = [];
@ -282,19 +282,50 @@ watch(() => new_style.value.common_style, () => {
})
}, {deep: true});
const swiper_bg_style = computed(() => {
if (!props.isCommon) {
return '';
}
const style = form.value?.carousel_list?.[actived_index.value]?.style;
if (style && !isEmpty(style.color_list)) {
const color_list = style.color_list;
const list = color_list.filter((item: { color: string }) => !isEmpty(item.color));
if (list.length > 0) {
try {
return gradient_computer(style);
} catch (error) {
return '';
}
}
return '';
}
return '';
});
const swiper_bg_img_style = computed(() => {
if (!props.isCommon) {
return '';
}
if (!isEmpty(form.value.carousel_list[actived_index.value].style.background_img)) {
return background_computer(form.value.carousel_list[actived_index.value].style);
}
return '';
});
const emit = defineEmits(['slideChange']);
const slideChange = (swiper: { realIndex: number }) => {
if (swiper.realIndex > form.value.carousel_list.length - 1) {
if (swiper.realIndex > form.value.carousel_list.length - 1 && form.value.carousel_type == 'card') {
const seat_length = seat_list.value.length;
if (seat_length == 2 && swiper.realIndex == 3) {
actived_index.value = 1;
} else if (seat_length == 3) {
actived_index.value = 0;
} else {
actived_index.value = swiper.realIndex - seat_list.value.length;
actived_index.value = 0;
}
} else {
actived_index.value = swiper.realIndex;
}
if (!props.isCommon) {
emit('slideChange', actived_index.value);
}
}
</script>
<style lang="scss" scoped>

View File

@ -31,27 +31,44 @@
<div class="divider-line"></div>
<card-container>
<div class="mb-12">内容设置</div>
<div class="tips mt-10 mb-20 size-12">最多添加{{ form.carousel_list.length }}张图片建议尺寸750*300px</div>
<div class="tips mt-10 mb-20 size-12">最多添加{{ carousel_list.length }}张图片建议尺寸750*300px</div>
<div class="flex-col gap-20">
<div v-for="(item, index) in form.carousel_list" :key="index" class="card-background box-shadow-sm re">
<div class="flex-col align-c jc-c gap-20 w">
<div class="upload_style">
<upload v-model="item.carousel_img" :limit="1" size="100%">
<span class="upload-text">上传图片</span>
</upload>
</div>
<el-form-item label="图片链接" class="w">
<url-value v-model="item.carousel_link"></url-value>
</el-form-item>
<div class="upload_style">
<upload v-model="item.carousel_video" :limit="1" type="video" size="100%">
<span class="upload-text">上传视频</span>
</upload>
</div>
<el-form-item v-if="item.carousel_video.length > 0" label="按钮名称" class="w">
<el-input v-model="item.video_title" placeholder="请输入视频按钮名称" clearable></el-input>
</el-form-item>
</div>
<div v-for="(item, index) in carousel_list" :key="index" class="card-background box-shadow-sm re">
<el-tabs v-model="item.tabs_name" class="content-tabs">
<el-tab-pane label="内容设置" name="content">
<div class="flex-col align-c jc-c gap-20 w">
<div class="upload_style">
<upload v-model="item.carousel_img" :limit="1" size="100%">
<span class="upload-text">上传图片</span>
</upload>
</div>
<el-form-item label="图片链接" class="w">
<url-value v-model="item.carousel_link"></url-value>
</el-form-item>
<div class="upload_style">
<upload v-model="item.carousel_video" :limit="1" type="video" size="100%">
<span class="upload-text">上传视频</span>
</upload>
</div>
<el-form-item v-if="item.carousel_video.length > 0" label="按钮名称" class="w">
<el-input v-model="item.video_title" placeholder="请输入视频按钮名称" clearable></el-input>
</el-form-item>
</div>
</el-tab-pane>
<el-tab-pane label="样式设置" name="styles">
<el-form-item label-width="0">
<div class="flex-col gap-10 w">
<div class="size-12">背景色</div>
<mult-color-picker :value="item.style.color_list" :type="item.style.direction" @update:value="(...value: [color_list[], number]) => carousel_tabs_mult_color_picker_event(...value, index)"></mult-color-picker>
<div class="flex-row jc-sb align-c">
<div class="size-12">背景图</div>
<bg-btn-style v-model="item.style.background_img_style"></bg-btn-style>
</div>
<upload v-model="item.style.background_img" :limit="1" @update:model-value="carousel_tabs_background_img_change($event, index)"></upload>
</div>
</el-form-item>
</el-tab-pane>
</el-tabs>
<el-icon class="iconfont icon-close-fillup size-16 abs cr-c top-de-5 right-de-5" @click="remove(index)" />
</div>
</div>
@ -61,6 +78,7 @@
</div>
</template>
<script setup lang="ts">
import { isEmpty } from "lodash";
const props = defineProps({
value: {
type: Object,
@ -72,24 +90,56 @@ const state = reactive({
form: props.value,
});
const { form } = toRefs(state);
const carousel_list = computed(() => {
form.value.carousel_list.forEach((item: any) => {
item.tabs_name = "content";
if (isEmpty(item.style)) {
item.style = {
direction: '90deg',
color_list: [{ color: '', color_percentage: undefined }],
background_img_style: '2',
background_img: [],
}
}
});
return form.value.carousel_list;
});
const add = () => {
form.value.carousel_list.push({
carousel_img: [],
carousel_video: [],
carousel_link: {},
video_title: "视频名称"
video_title: "视频名称",
style: {
direction: '90deg',
color_list: [{ color: '', color_percentage: undefined }],
background_img_style: '2',
background_img: [],
}
});
};
const remove = (index: number) => {
form.value.carousel_list.splice(index, 1);
};
//
const carousel_tabs_mult_color_picker_event = (arry: color_list[], type: number, index: number) => {
form.value.carousel_list[index].style.color_list = arry;
form.value.carousel_list[index].style.direction = type.toString();
};
//
const carousel_tabs_background_img_change = (arry: uploadList[], index: number) => {
form.value.carousel_list[index].style.background_img = arry;
};
</script>
<style lang="scss" scoped>
.card-background {
background: #fff;
padding-left: 1.6rem;
padding-right: 2rem;
padding-top: 4.6rem;
// padding-top: 4.6rem;
padding-bottom: 1.6rem;
:deep(.el-form-item) {
margin-bottom: 0;
@ -108,4 +158,25 @@ const remove = (index: number) => {
text-align: left;
font-style: normal;
}
:deep(.el-tabs.content-tabs) {
.el-tabs__header.is-top {
background: #fff;
margin: 0;
padding-top: 2rem;
padding-bottom: 1rem;
}
.el-tabs__item.is-top {
padding: 0;
align-items: center;
width: 10rem;
font-size: 1.4rem;
}
.el-tabs__content {
overflow: visible;
}
.el-tabs__active-bar{
width: 100%;
}
}
</style>

View File

@ -86,7 +86,7 @@ const init_data = () => {
//
const all_length = select_data.value.length;
// data_key
const list = select_data.value.filter((item: any) => item[props.dataListKey] == undefined );
const list = select_data.value.filter((item: any) => item[props.dataListKey] == null );
if (list.length == 0) {
return true;
} else {

View File

@ -290,7 +290,7 @@ const filter_data_handling = (type: string = 'old') => {
}
// 使
if (type == 'old') {
staging_data[item.form_name] = form.value.data_source_content[item.form_name] == undefined ? value : form.value.data_source_content[item.form_name];
staging_data[item.form_name] = form.value.data_source_content[item.form_name] == null ? value : form.value.data_source_content[item.form_name];
} else {
staging_data[item.form_name] = value;
}

View File

@ -22,6 +22,16 @@
<el-form-item label="未选图标">
<color-text-size-group v-model:color="form.tabs_icon_color" v-model:size="form.tabs_icon_size" default-color="rgba(51,51,51,1)" slider-name="" :type-list="['color', 'size']" />
</el-form-item>
<el-form-item v-if="['4'].includes(data.tabs_theme)" label="标题上图">
<div class="flex-col gap-10 w">
<el-form-item label="圆角" label-width="40">
<radius :value="form.tabs_top_img_radius"></radius>
</el-form-item>
<el-form-item label="高度" label-width="40">
<slider v-model="form.tabs_top_img_height" :max="200"></slider>
</el-form-item>
</div>
</el-form-item>
<el-form-item label="图片设置">
<div class="flex-col gap-10 w">
<template v-if="['2', '4'].includes(data.tabs_theme)">

View File

@ -1,6 +1,6 @@
<template>
<div :style="style_container">
<div class="flex-col oh" :style="style_img_container">
<div :style="style_container + swiper_bg_style">
<div class="flex-col oh" :style="style_img_container + swiper_bg_img_style">
<div class="oh" :style="tabs_container">
<div class="oh" :style="tabs_img_container">
<tabs-view ref="tabs" :value="tabs_list" :is-tabs="true" :active-index="tabs_active_index"></tabs-view>
@ -8,7 +8,7 @@
</div>
<div class="oh" :style="carousel_container">
<div class="oh" :style="carousel_img_container">
<model-carousel :value="value" :is-common="false"></model-carousel>
<model-carousel :value="value" :is-common="false" @slide-change="slideChange"></model-carousel>
</div>
</div>
</div>
@ -16,7 +16,7 @@
</template>
<script setup lang="ts">
import { common_styles_computer, common_img_computer, padding_computer, gradient_computer, background_computer, margin_computer, radius_computer } from '@/utils';
import { cloneDeep } from 'lodash';
import { cloneDeep, isEmpty } from 'lodash';
const props = defineProps({
value: {
type: Object,
@ -67,5 +67,35 @@ watch(
const style_container = computed(() => `${common_styles_computer(props.value.style.common_style)};`);
const style_img_container = computed(() => `${common_img_computer(props.value.style.common_style)};gap:${props.value.style.data_spacing}px`);
const form = computed(() => props.value.content);
const actived_index = ref(0);
const slideChange = (index: number) => {
actived_index.value = index;
};
const swiper_bg_style = computed(() => {
const style = form.value?.carousel_list?.[actived_index.value]?.style;
if (style && !isEmpty(style.color_list)) {
const color_list = style.color_list;
const list = color_list.filter((item: { color: string }) => !isEmpty(item.color));
if (list.length > 0) {
try {
return gradient_computer(style);
} catch (error) {
return '';
}
}
return '';
}
return '';
});
const swiper_bg_img_style = computed(() => {
if (!isEmpty(form.value?.carousel_list[actived_index.value]?.style?.background_img)) {
return background_computer(form.value.carousel_list[actived_index.value].style);
}
return '';
});
</script>
<style lang="scss" scoped></style>

View File

@ -11,8 +11,8 @@
</el-radio-group>
</el-form-item>
<el-form-item label="滑动置顶">
<el-switch v-model="form.tabs_top_up" class="mr-10" active-value="1" inactive-value="0"></el-switch>
<el-tooltip effect="dark" :show-after="200" :hide-after="200" content="滑动置顶仅手机端有效" raw-content placement="top">
<el-switch v-model="form.tabs_top_up" class="mr-10" active-value="1" inactive-value="0" :disabled="is_immersion_model" />
<el-tooltip effect="dark" :show-after="200" :hide-after="200" content="<span>1.开启沉浸样式时,选项卡置顶功能禁用</span><br/><span>2.滑动置顶仅手机端有效</span>" raw-content placement="top">
<icon name="miaosha-hdgz" size="12" color="#999"></icon>
</el-tooltip>
</el-form-item>
@ -80,6 +80,8 @@
</template>
<script setup lang="ts">
import { get_math, tabs_style } from '@/utils';
import { commonStore } from '@/store';
const common_store = commonStore();
const props = defineProps({
value: {
@ -123,6 +125,13 @@ const on_sort = (new_list: nav_group[]) => {
const tabs_theme_change = (val: string | number | boolean | undefined): void => {
styles.value.tabs_color_checked = tabs_style(styles.value.tabs_color_checked, val);
};
//
const is_immersion_model = computed(() => common_store.is_immersion_model);
watchEffect(() => {
if (is_immersion_model.value) {
form.value.tabs_top_up = '0';
}
});
</script>
<style lang="scss" scoped>
.cursor-move {

View File

@ -30,7 +30,7 @@
</el-form-item>
<el-form-item v-if="form.header_background_type == 'transparent'" label="沉浸样式">
<div class="flex-row align-c gap-10">
<el-switch v-model="form.immersive_style" active-value="1" inactive-value="0" :disabled="is_have_tabs" @change="change_immersive_style"></el-switch>
<el-switch v-model="form.immersive_style" active-value="1" inactive-value="0" @change="change_immersive_style"></el-switch>
<el-tooltip effect="dark" :show-after="200" :hide-after="200" content="<span>开启沉浸样式时,不可添加选项卡和选项卡轮播。<br/>并且商品选项卡和文章选项卡的选项卡置顶功能禁用</span>" raw-content placement="top">
<icon name="miaosha-hdgz" size="12" color="#999"></icon>
</el-tooltip>
@ -185,10 +185,6 @@ const props = defineProps({
default: () => {},
},
});
const is_have_tabs = computed(() => {
return common_store.is_have_tabs;
});
const emit = defineEmits(['update:value']);
const state = reactive({
form: props.value,
@ -210,10 +206,10 @@ const header_background_type_change_event = (val: any) => {
common_store.set_is_immersion_model(false);
} else {
// tabs
if (!common_store.is_have_tabs) {
form.value.immersive_style = '1';
common_store.set_is_immersion_model(true);
}
// if (!common_store.is_have_tabs) {
form.value.immersive_style = '1';
common_store.set_is_immersion_model(true);
// }
}
};

View File

@ -6,6 +6,12 @@ interface carousel_list {
carousel_video: uploadList[];
carousel_link: object;
video_title: string;
style: {
direction: string;
color_list: color_list[];
background_img_style: string;
background_img: uploadList[];
}
}
interface defaultSearch {
content: {
@ -61,19 +67,37 @@ const defaultSearch: defaultSearch = {
carousel_img: [],
carousel_video: [],
carousel_link: {},
video_title: '视频名称'
video_title: '视频名称',
style: {
direction: '90deg',
color_list: [{ color: '', color_percentage: undefined }],
background_img_style: '2',
background_img: [],
}
},
{
carousel_img: [],
carousel_video: [],
carousel_link: {},
video_title: '视频名称'
video_title: '视频名称',
style: {
direction: '90deg',
color_list: [{ color: '', color_percentage: undefined }],
background_img_style: '2',
background_img: [],
}
},
{
carousel_img: [],
carousel_video: [],
carousel_link: {},
video_title: '视频名称'
video_title: '视频名称',
style: {
direction: '90deg',
color_list: [{ color: '', color_percentage: undefined }],
background_img_style: '2',
background_img: [],
}
}
]
},

View File

@ -59,6 +59,8 @@ interface DefaultProductList {
tabs_icon_color: string,
tabs_icon_size: number,
is_tabs_img_background: string,
tabs_top_img_radius: radiusStyle;
tabs_top_img_height: number;
tabs_img_radius: radiusStyle,
tabs_img_height: number,
tabs_spacing: number;
@ -181,6 +183,14 @@ const defaultProductList: DefaultProductList = {
tabs_icon_size_checked: 14,
tabs_icon_color: 'rgba(51,51,51,1)',
tabs_icon_size: 14,
tabs_top_img_radius: {
radius: 100,
radius_top_left: 100,
radius_top_right: 100,
radius_bottom_left: 100,
radius_bottom_right: 100,
},
tabs_top_img_height: 39,
is_tabs_img_background: '0',
tabs_img_radius: {
radius: 0,

View File

@ -18,6 +18,12 @@ interface carousel_list {
carousel_video: uploadList[];
carousel_link: object;
video_title: string;
style: {
direction: string;
color_list: color_list[];
background_img_style: string;
background_img: uploadList[];
}
}
interface defaultTabs {
content: {
@ -104,7 +110,7 @@ const defaultTabs: defaultTabs = {
// 选项卡风格
tabs_theme: '0',
// 是否置顶
tabs_top_up: '1',
tabs_top_up: '0',
// 选项卡数据
home_data: { id: get_math(), tabs_type: '0', tabs_img: [], tabs_icon: '', title: '首页', desc: '简介', data_type: '0', classify: {}, micro_page: '', micro_page_list: {}, category_list: {} },
tabs_list: [
@ -126,18 +132,36 @@ const defaultTabs: defaultTabs = {
carousel_video: [],
carousel_link: {},
video_title: '视频名称',
style: {
direction: '90deg',
color_list: [{ color: '', color_percentage: undefined }],
background_img_style: '2',
background_img: [],
}
},
{
carousel_img: [],
carousel_video: [],
carousel_link: {},
video_title: '视频名称',
style: {
direction: '90deg',
color_list: [{ color: '', color_percentage: undefined }],
background_img_style: '2',
background_img: [],
}
},
{
carousel_img: [],
carousel_video: [],
carousel_link: {},
video_title: '视频名称',
style: {
direction: '90deg',
color_list: [{ color: '', color_percentage: undefined }],
background_img_style: '2',
background_img: [],
}
},
],
// 轮播高度

View File

@ -49,7 +49,7 @@ interface defaultTabs {
const defaultTabs: defaultTabs = {
content: {
tabs_theme: '0',
tabs_top_up: '1',
tabs_top_up: '0',
home_data: { id: get_math(), tabs_type: '0', tabs_img: [], tabs_icon: '', title: '首页', desc: '简介', data_type: '0', classify: {}, micro_page: '', micro_page_list: {}, category_list: {} },
tabs_list: [
{ id: get_math(), tabs_type: '0', tabs_img: [], tabs_icon: '', title: '热门推荐', desc: '简介', data_type: '0', classify: {}, micro_page: '', micro_page_list: {}, category_list: {} },

View File

@ -388,11 +388,11 @@ export const percentage_count = (num: number, container_size: number) => {
* @returns boolean truefalse
*/
export const areAllEqual = (a: number, b: number, c: number, d: number) => {
if (a === null || a === undefined || b === null || b === undefined || c === null || c === undefined || d === null || d === undefined) {
return false;
if (a == null || b == null || c == null || d == null) {
return false;
}
return a === b && b === c && c === d;
}
}
/**
*

View File

@ -159,7 +159,11 @@ const outer_container_padding = ref(0);
const bottom_navigation_show = ref(true);
//
const set_padding_top_value = () => {
if (diy_data.value.length > 0) {
if (tabs_data.value.length > 0) {
tabs_data.value.forEach((item: any) => {
item.com_data.style.common_style.padding_top_safe_value = common_store.header_height;
});
} else if (diy_data.value.length > 0) {
// 0
let padding_top_index = 0;
//
@ -263,12 +267,10 @@ const show_model_border = ref(true);
const draggable_click = (item: componentsData) => {
const type_data = ['tabs', 'tabs-carousel'];
if (type_data.includes(item.key)) {
if (common_store.is_immersion_model) {
ElMessage.error('开启沉浸样式下不可以添加该组件');
return;
}
// if (common_store.is_immersion_model) {
// ElMessage.error('');
// return;
// }
if (isEmpty(tabs_data.value)) {
// tabs
tabs_data.value.push({
@ -281,7 +283,7 @@ const draggable_click = (item: componentsData) => {
key: item.key,
com_data: cloneDeep((defaultSettings as any)[item.key.replace(/-/g, '_')]),
});
common_store.set_is_have_tabs(true);
// common_store.set_is_have_tabs(true);
set_tabs_event(true);
} else if (!isEmpty(tabs_data.value)) {
if (tabs_data.value[0].key == item.key) {
@ -292,11 +294,11 @@ const draggable_click = (item: componentsData) => {
}
}
};
watchEffect(() => {
if (tabs_data.value.length <= 0) {
common_store.set_is_have_tabs(false);
}
});
// watchEffect(() => {
// if (tabs_data.value.length <= 0) {
// common_store.set_is_have_tabs(false);
// }
// });
//
const clone_item_com_data = (item: commonComponentData) => {