源文件
This commit is contained in:
430
components/diy/article-list.vue
Normal file
430
components/diy/article-list.vue
Normal file
@@ -0,0 +1,430 @@
|
||||
<template>
|
||||
<!-- 文章列表 -->
|
||||
<view class="oh" :style="style_container">
|
||||
<view class="oh" :style="style_img_container">
|
||||
<view class="pr oh" :style="style">
|
||||
<view v-if="!['4'].includes(article_theme)" class="flex-wrap" :class="article_theme_class" :style="article_theme !== '3' ? article_spacing : ''">
|
||||
<view v-for="(item, index) in data_list" :key="index" class="item oh" :style="article_style" :data-value="item.data.url" @tap="url_event">
|
||||
<view :class="article_theme == '0' ? 'flex-row oh' : 'flex-col oh ht-auto'" :style="article_img_style">
|
||||
<template v-if="article_theme !== '3'">
|
||||
<view class="oh pr flex-row">
|
||||
<template v-if="item.new_cover.length > 0">
|
||||
<image :src="item.new_cover[0].url" class="img" :style="img_radius + img_size" mode="aspectFill" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<image :src="item.data.cover" class="img" :style="img_radius + img_size" mode="aspectFill" />
|
||||
</template>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="field_show.includes('0') || field_show.includes('1') || field_show.includes('2') || field_show.includes('3')" class="jc-sb flex-1" :class="article_theme == '3' ? 'flex-row align-c' : 'flex-col'" :style="article_theme !== '0' ? content_padding : ''">
|
||||
<view class="flex-col" :class="article_theme == '3' ? 'flex-1 flex-width' : ''" :style="'gap:' + name_desc_space + 'px;'">
|
||||
<view v-if="field_show.includes('3')" class="title" :class="article_theme == '3' ? 'text-line-1' : 'text-line-2'" :style="article_name">{{ item.new_title ? item.new_title : item.data.title }}</view>
|
||||
<view v-if="field_show.includes('2')" :class="'desc ' + field_desc_row == '2' ? 'text-line-2' : 'text-line-1'" :style="article_desc">{{ item.data.describe || '' }}</view>
|
||||
</view>
|
||||
<view class="flex-row jc-sb gap-8" :class="article_theme == '3' ? 'margin-left' : 'align-e margin-top'">
|
||||
<view :style="article_date">{{ field_show.includes('0') ? item.data.add_time : '' }}</view>
|
||||
<view v-show="field_show.includes('1')" class="flex-row align-c gap-3" :style="article_page_view">
|
||||
<iconfont name="icon-eye" propContainerDisplay="flex"></iconfont>
|
||||
<view>
|
||||
{{ item.data.access_count ? item.data.access_count : '' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="oh" :class="article_theme_class">
|
||||
<swiper class="swiper" circular :autoplay="is_roll ? true : false" :interval="interval_time" :next-margin="next_margin" :display-multiple-items="slides_per_group" :style="'height:' + carousel_height_computer">
|
||||
<swiper-item v-for="(item1, index1) in article_carousel_list" :key="index1">
|
||||
<view class="flex-row ht-auto" :style="article_spacing">
|
||||
<view v-for="(item, index) in item1.carousel_list" :key="index" class="item oh ht-auto" :style="article_style" :data-value="item.data.url" @tap="url_event">
|
||||
<view class="oh flex-col ht-auto" :style="article_img_style">
|
||||
<view class="oh pr wh-auto ht-auto flex-row">
|
||||
<template v-if="item.new_cover.length > 0">
|
||||
<image :src="item.new_cover[0].url" class="img" :style="img_radius + 'height:100%;'" mode="aspectFill" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<image :src="item.data.cover" class="img" :style="img_radius + 'height:100%;'" mode="aspectFill" />
|
||||
</template>
|
||||
<template v-if="field_show.includes('3') && name_float == '1'">
|
||||
<view class="text-line-1" :style="article_name + float_name_style">{{ item.new_title ? item.new_title : item.data.title }}</view>
|
||||
</template>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
<view v-if="field_show.includes('0') || field_show.includes('1') || field_show.includes('2') || (field_show.includes('3') && name_float == '0')" class="jc-sb flex-1 flex-col" :style="article_theme !== '0' ? content_padding : ''">
|
||||
<view class="flex-col" :style="'gap:' + name_desc_space + 'px;'">
|
||||
<view v-if="field_show.includes('3') && name_float == '0'" class="title text-line-2" :style="article_name + article_name_height_computer">{{ item.new_title ? item.new_title : item.data.title }}</view>
|
||||
<view v-if="field_show.includes('2')" :class="'desc ' + field_desc_row == '2' ? 'text-line-2' : 'text-line-1'" :style="article_desc">{{ item.data.describe || '' }}</view>
|
||||
</view>
|
||||
<view :class="'flex-row jc-sb gap-8 align-e' + ((field_show.includes('3') && name_float == '0') || field_show.includes('2') ? ' margin-top' : '')">
|
||||
<view :style="article_date">{{ field_show.includes('0') ? item.data.add_time : '' }}</view>
|
||||
<view v-show="field_show.includes('1')" class="flex-row align-c gap-3" :style="article_page_view">
|
||||
<iconfont name="icon-eye" propContainerDisplay="flex"></iconfont>
|
||||
<view>
|
||||
{{ item.data.access_count ? item.data.access_count : '' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty, common_styles_computer, common_img_computer, padding_computer, radius_computer, get_math, gradient_handle, background_computer, gradient_computer, margin_computer, box_shadow_computer, border_computer, old_margin } from '@/common/js/common/common.js';
|
||||
import subscriptIndex from '@/components/diy/modules/subscript/index.vue';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
subscriptIndex,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
// 是否使用公共样式
|
||||
propIsCommonStyle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 关键key
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
// 数据
|
||||
data_list: [],
|
||||
// 风格
|
||||
article_theme: '0',
|
||||
|
||||
// 是否显示
|
||||
field_show: ['0', '1'],
|
||||
// 文章
|
||||
article_name: '',
|
||||
// 描述
|
||||
article_desc: '',
|
||||
// 日期
|
||||
article_date: '',
|
||||
// 浏览量
|
||||
article_page_view: '',
|
||||
// 内容圆角
|
||||
content_radius: '',
|
||||
// 图片圆角
|
||||
img_radius: '',
|
||||
// 内间距
|
||||
content_padding: '',
|
||||
// 内容间距
|
||||
content_spacing: '',
|
||||
// 文章间距
|
||||
article_spacing: '',
|
||||
// article_item_height: '',
|
||||
|
||||
article_style: '',
|
||||
article_img_style: '',
|
||||
// 轮播图定时轮播
|
||||
interval_time: 2000,
|
||||
// 轮播图是否滚动
|
||||
is_roll: 1,
|
||||
|
||||
article_theme_class: '',
|
||||
// 轮播高度
|
||||
carousel_height_computer: '',
|
||||
// 文章内容高度
|
||||
article_name_height_computer: '',
|
||||
// 文章名称浮动样式
|
||||
float_name_style: '',
|
||||
name_float: '0',
|
||||
// 图片大小
|
||||
img_size: '',
|
||||
// 文章轮播数据
|
||||
article_carousel_list: [],
|
||||
// 文章描述间距
|
||||
name_desc_space: 0,
|
||||
// 一行显示的数量
|
||||
slides_per_group: 1,
|
||||
next_margin: '0rpx',
|
||||
field_desc_row: '1',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
// 描述样式
|
||||
const desc_size = new_style.desc_size;
|
||||
let desc_style = 'font-size:' + desc_size + 'px;line-height:' + desc_size + 'px;height:' + desc_size + 'px;color:' + new_style.desc_color + ';';
|
||||
if (new_content.field_desc_row == '2') {
|
||||
desc_style = 'font-size:' + desc_size + 'px;line-height:' + (desc_size > 0 ? desc_size + 3 : 0 ) + 'px;height:'+ (desc_size > 0 ? (desc_size + 3) * 2 : 0) + 'px;color:' + new_style.desc_color + ';';
|
||||
}
|
||||
this.setData({
|
||||
field_desc_row: new_content.field_desc_row,
|
||||
name_float: !isEmpty(new_content.name_float) ? new_content.name_float : '0',
|
||||
// 判断是自动还是手动
|
||||
data_list:
|
||||
new_content.data_type == '0'
|
||||
? new_content.data_list
|
||||
: new_content.data_auto_list && new_content.data_auto_list.length > 0
|
||||
? new_content.data_auto_list.map((item) => ({
|
||||
id: get_math(),
|
||||
new_title: '',
|
||||
new_cover: [],
|
||||
data: item,
|
||||
}))
|
||||
: [],
|
||||
article_theme_class: this.article_theme_class_computer(new_content.theme),
|
||||
article_theme: new_content.theme,
|
||||
field_show: new_content.field_show,
|
||||
// 样式
|
||||
article_name: 'font-size:' + new_style.name_size + 'px;' + 'font-weight:' + new_style.name_weight + ';' + 'color:' + new_style.name_color + ';',
|
||||
article_desc: desc_style,
|
||||
article_date: 'font-size:' + new_style.time_size + 'px;' + 'font-weight:' + new_style.time_weight + ';' + 'color:' + new_style.time_color + ';',
|
||||
article_page_view: 'font-size:' + new_style.page_view_size + 'px;' + 'font-weight:' + new_style.page_view_weight + ';' + 'color:' + new_style.page_view_color + ';',
|
||||
content_radius: radius_computer(new_style.content_radius),
|
||||
img_radius: radius_computer(new_style.img_radius),
|
||||
// 内间距
|
||||
content_padding: padding_computer(new_style.padding),
|
||||
// 内容间距
|
||||
content_spacing: `gap: ${new_style.content_spacing}px;`,
|
||||
// 文章间距
|
||||
article_spacing: `gap: ${new_style.article_spacing}px;`,
|
||||
// 描述间距
|
||||
name_desc_space: parseInt(new_style.name_desc_space),
|
||||
next_margin: new_style.rolling_fashion == 'translation' ? '-' + new_style.article_spacing_margin + 'px' : '0rpx',
|
||||
// 文章内容高度
|
||||
slides_per_group: new_style.rolling_fashion == 'translation' ? Number(new_content.carousel_col) + 1 : 1,
|
||||
|
||||
});
|
||||
// 默认数据
|
||||
const product_style_list = [
|
||||
{ name: '单列展示', value: '0', width:110, height: 83 },
|
||||
{ name: '两列展示(纵向)', value: '1', width:180, height: 180 },
|
||||
{ name: '大图展示', value: '2', width:0, height: 180 },
|
||||
{ name: '无图模式', value: '3', width:0, height: 0 },
|
||||
{ name: '左右滑动展示', value: '4', width:0, height: 0 },
|
||||
];
|
||||
const scale = sys_width / 390;
|
||||
let img_style = ``;
|
||||
if (['0'].includes(new_content.theme)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_width == 'number') {
|
||||
img_style += `width: ${ new_style.content_img_width * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_content.theme);
|
||||
if (list.length > 0) {
|
||||
img_style += `width: ${ list[0].width * scale }px;`;
|
||||
} else {
|
||||
img_style += 'width: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!['3', '4'].includes(new_content.theme)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_height == 'number') {
|
||||
img_style += `height: ${ new_style.content_img_height * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_content.theme);
|
||||
if (list.length > 0) {
|
||||
img_style += `height: ${ list[0].height * scale }px;`;
|
||||
} else {
|
||||
img_style += 'height: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
// 背景图的处理
|
||||
const article_data = {
|
||||
background_img_style: new_style?.article_background_img_style || '',
|
||||
background_img: new_style?.article_background_img || '',
|
||||
}
|
||||
const article_margin = new_style.value?.margin || old_margin;
|
||||
const margin_width = article_margin.margin_left + article_margin.margin_right;
|
||||
// 渐变效果
|
||||
const all_style = gradient_handle(new_style?.article_color_list || [], new_style?.article_direction || '') + margin_computer(article_margin) + box_shadow_computer(new_style) + border_computer(new_style);
|
||||
// 文章样式
|
||||
if (this.article_theme == '0') {
|
||||
this.setData({
|
||||
img_size: img_style,
|
||||
article_style: this.content_radius + all_style,
|
||||
article_img_style: this.content_spacing + this.content_padding + background_computer(article_data)
|
||||
});
|
||||
} else if (this.article_theme == '1') {
|
||||
this.setData({
|
||||
img_size: img_style,
|
||||
article_style: `width: calc(50% - ${new_style.article_spacing + (margin_width * 2) / 2}px);` + this.content_radius + all_style,
|
||||
article_img_style: background_computer(article_data)
|
||||
});
|
||||
} else if (this.article_theme == '2') {
|
||||
this.setData({
|
||||
img_size: img_style,
|
||||
article_style: this.content_radius + all_style,
|
||||
article_img_style: background_computer(article_data)
|
||||
});
|
||||
} else if (this.article_theme == '3') {
|
||||
this.setData({
|
||||
style: `padding: 0 ${new_style.content_spacing}px;background:#fff;` + this.content_radius,
|
||||
});
|
||||
} else if (this.article_theme == '4') {
|
||||
// 更新轮播图的key,确保更换时能重新更新轮播图
|
||||
const temp_carousel_col = new_content.carousel_col || '1';
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = temp_carousel_col !== '0' ? ((new_style.article_spacing * temp_carousel_col - 1) + (margin_width * temp_carousel_col)) / temp_carousel_col : '0';
|
||||
const multicolumn_columns_width = new_style.rolling_fashion == 'translation' ? `margin-right: ${ new_style.article_spacing + article_margin.margin_right }px;width:100%;` : `width:calc(${100 / (Number(temp_carousel_col) + 1)}% - ${gap * 2}rpx);min-width:calc(${100 / (Number(temp_carousel_col) + 1)}% - ${gap * 2}rpx);`;
|
||||
const { name_bg_color_list = [], name_bg_direction = '180deg', name_bg_radius, name_bg_padding, name_bg_margin } = new_style;
|
||||
const data = {
|
||||
color_list: name_bg_color_list,
|
||||
direction: name_bg_direction,
|
||||
}
|
||||
let location = 'position:absolute;bottom:0;left:0;right:0;'
|
||||
// 轮播宽度
|
||||
this.setData({
|
||||
// 滚动时间
|
||||
interval_time: (new_style.interval_time || 2) * 1000,
|
||||
// 是否滚动修改
|
||||
is_roll: new_style.is_roll,
|
||||
// article_item_height: `height: ${new_style.article_height }px`,
|
||||
article_style: this.content_radius + all_style + multicolumn_columns_width,
|
||||
// 轮播高度
|
||||
carousel_height_computer: new_style.article_height * scale + 'px',
|
||||
// 文章内容高度
|
||||
article_name_height_computer: `height:${new_style.name_size * 2.4 * 2}rpx;line-height:${new_style.name_size * 1.2 * 2}rpx;`,
|
||||
float_name_style: gradient_computer(data) + (!isEmpty(name_bg_radius) ? radius_computer(name_bg_radius) : '') + (!isEmpty(name_bg_padding) ? padding_computer(name_bg_padding) : '' ) + (!isEmpty(name_bg_padding) ? margin_computer(name_bg_margin) : '') + location,
|
||||
article_img_style: background_computer(article_data)
|
||||
});
|
||||
// 文章轮播数据
|
||||
const cloneList = JSON.parse(JSON.stringify(this.data_list));
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (new_style.rolling_fashion != 'translation') {
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = Number(temp_carousel_col) + 1;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({ carousel_list: cloneList.slice(i * num, (i + 1) * num) });
|
||||
}
|
||||
this.setData({
|
||||
article_carousel_list: nav_list,
|
||||
});
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
this.setData({
|
||||
article_carousel_list: [{ carousel_list: cloneList }],
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
carousel_list: [item],
|
||||
});
|
||||
});
|
||||
this.setData({
|
||||
article_carousel_list: nav_list,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.propIsCommonStyle) {
|
||||
this.setData({
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
}
|
||||
},
|
||||
// 文章主题样式
|
||||
article_theme_class_computer(theme) {
|
||||
switch (theme) {
|
||||
case '0':
|
||||
return 'style1 flex-col';
|
||||
case '1':
|
||||
return 'style2 flex-row flex-wrap';
|
||||
case '2':
|
||||
return 'style3 flex-col';
|
||||
case '3':
|
||||
return 'style4 flex-col';
|
||||
default:
|
||||
return 'style5';
|
||||
}
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.style1 {
|
||||
.item {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
.style2 {
|
||||
.item {
|
||||
.img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.style3 {
|
||||
.item {
|
||||
width: 100%;
|
||||
.img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.style4 {
|
||||
.item {
|
||||
width: 100%;
|
||||
&:not(:last-child) {
|
||||
border-bottom: 2rpx solid #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
.style5 {
|
||||
.item {
|
||||
width: 100%;
|
||||
.img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
264
components/diy/article-tabs.vue
Normal file
264
components/diy/article-tabs.vue
Normal file
@@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<!-- 文章列表 -->
|
||||
<view class="article-tabs ou" :class="'article-tabs-' + propKey" :style="style_container">
|
||||
<view class="ou" :style="style_img_container">
|
||||
<componentDiyModulesTabsView :propKey="propKey" :propValue="article_tabs" :propIsTop="top_up == '1'" :propTop="sticky_top" :propStyle="tabs_style" :propsTabsContainer="tabs_container" :propsTabsImgContainer="tabs_img_container" :propCustomNavHeight="propIsTabsUseSafeDistance ? (propCustomNavHeight * 2 + 'rpx') : '0rpx'" :propTabsBackground="tabs_background" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" @onTabsTap="tabs_click_event"></componentDiyModulesTabsView>
|
||||
<view :style="article_margin_top">
|
||||
<view :style="article_container">
|
||||
<view :style="article_img_container">
|
||||
<componentDiyArticleList :propKey="diy_key" :propValue="article_tabs" :propIsCommonStyle="false"></componentDiyArticleList>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, margin_computer, background_computer, gradient_computer, radius_computer, isEmpty, box_shadow_computer, border_computer, old_border_and_box_shadow, old_margin, old_padding } from '@/common/js/common/common.js';
|
||||
import componentDiyModulesTabsView from '@/components/diy/modules/tabs-view';
|
||||
import componentDiyArticleList from '@/components/diy/article-list'; // 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
// 距离顶部高度
|
||||
propTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 自定义导航栏高度
|
||||
propCustomNavHeight: {
|
||||
type: Number,
|
||||
default: 33,
|
||||
},
|
||||
// 滚动距离
|
||||
propScrollTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 顶部导航是否开启沉浸模式
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
// 选项卡是否使用安全距离
|
||||
propIsTabsUseSafeDistance: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
components: {
|
||||
componentDiyModulesTabsView,
|
||||
componentDiyArticleList,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
article_tabs: {},
|
||||
// 是否滑动置顶
|
||||
top_up: '0',
|
||||
tabs_style: '',
|
||||
tabs_top: 0,
|
||||
tabs_background: 'background:transparent',
|
||||
custom_nav_height: 33,
|
||||
diy_key: '',
|
||||
// 选项卡背景设置
|
||||
article_margin_top: '',
|
||||
tabs_container: '',
|
||||
tabs_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
// 商品区域背景设置
|
||||
article_container: '',
|
||||
article_img_container: '',
|
||||
// #ifdef MP
|
||||
nav_safe_space: bar_height + 5,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
nav_safe_space: bar_height + 7,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
nav_safe_space: bar_height + 0,
|
||||
// #endif
|
||||
// 选项卡默认数据
|
||||
tabs_index: 0,
|
||||
sticky_top: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听滚动距离
|
||||
propScrollTop(newVal) {
|
||||
if (newVal + this.sticky_top + this.custom_nav_height > this.tabs_top + this.nav_safe_space && this.top_up == '1') {
|
||||
let new_style = this.propValue.style || {};
|
||||
let tabs_bg = new_style.common_style.color_list;
|
||||
let new_tabs_background = '';
|
||||
if (tabs_bg.length > 0 && (tabs_bg[0].color || null) != null) {
|
||||
new_tabs_background = gradient_computer(new_style.common_style);
|
||||
}
|
||||
let new_tabs_background_img = background_computer(new_style.common_style);
|
||||
if (new_tabs_background_img.length > 0) {
|
||||
new_tabs_background_img += 'background-position: top left;';
|
||||
}
|
||||
this.tabs_background = (new_tabs_background.length > 0 ? new_tabs_background : 'background:#fff;') + new_tabs_background_img;
|
||||
} else {
|
||||
this.tabs_background = 'background:transparent';
|
||||
}
|
||||
},
|
||||
propTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
this.setData({
|
||||
diy_key: val,
|
||||
});
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const self = this;
|
||||
setTimeout(() => {
|
||||
self.getTop();
|
||||
});
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// 获取自定义导航栏高度
|
||||
this.setData({
|
||||
custom_nav_height: this.propCustomNavHeight,
|
||||
});
|
||||
// #endif
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
let new_content = this.propValue.content || {};
|
||||
let new_style = this.propValue.style || {};
|
||||
let new_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
|
||||
const new_tabs_data = new_data.content.tabs_list[this.tabs_index] || {};
|
||||
new_data.content.theme = new_data.content.article_theme;
|
||||
new_data.content.data_type = new_tabs_data.data_type;
|
||||
new_data.content.category = new_tabs_data.category;
|
||||
new_data.content.carousel_col = new_data.content.article_carousel_col;
|
||||
new_data.content.data_list = new_tabs_data.data_list;
|
||||
new_data.content.data_auto_list = new_tabs_data.data_auto_list;
|
||||
new_data.content.data_ids = new_tabs_data.data_ids;
|
||||
new_data.content.number = new_tabs_data.number;
|
||||
new_data.content.sort = new_tabs_data.sort;
|
||||
new_data.content.sort_rules = new_tabs_data.sort_rules;
|
||||
new_data.content.field_show = new_data.content.field_show;
|
||||
new_data.content.is_cover = new_tabs_data.is_cover;
|
||||
// 公共样式
|
||||
const common_style = new_style.common_style;
|
||||
let tabs_style_obj = {
|
||||
padding_top: common_style.padding_top - this.propCustomNavHeight < 0 ? 0 : common_style.padding_top - this.propCustomNavHeight,
|
||||
padding_left: common_style.padding_left,
|
||||
padding_right: common_style.padding_right,
|
||||
};
|
||||
let new_tabs_style = padding_computer(tabs_style_obj) + margin_computer(tabs_style_obj) + `position:relative;left: -${tabs_style_obj.padding_left * 2}rpx;right: -${tabs_style_obj.padding_right * 2}rpx;width:100%;`;
|
||||
// 如果是历史数据的话,就执行默认添加下边距
|
||||
if (isEmpty(new_style.tabs_padding)) {
|
||||
new_tabs_style += 'padding-bottom: 20rpx;';
|
||||
}
|
||||
const { tabs_bg_color_list = [], tabs_bg_direction = '', tabs_bg_background_img_style = '', tabs_bg_background_img = [], tabs_radius = old_radius, tabs_padding = old_padding, article_content_color_list = [], article_content_direction = '', article_content_background_img_style = '', article_content_background_img = [], article_content_margin = old_margin, article_content_padding = old_padding, article_content_radius = old_radius } = new_style;
|
||||
// 选项卡背景设置
|
||||
const tabs_data = {
|
||||
color_list: tabs_bg_color_list,
|
||||
direction: tabs_bg_direction,
|
||||
background_img_style: tabs_bg_background_img_style,
|
||||
background_img: tabs_bg_background_img,
|
||||
};
|
||||
// 文章区域背景设置
|
||||
const article_content_data = {
|
||||
color_list: article_content_color_list,
|
||||
direction: article_content_direction,
|
||||
background_img_style: article_content_background_img_style,
|
||||
background_img: article_content_background_img,
|
||||
};
|
||||
const article_content = new_style?.article_content || old_border_and_box_shadow;
|
||||
const tabs_content = new_style?.tabs_content || old_border_and_box_shadow;
|
||||
this.setData({
|
||||
top_up: new_content.tabs_top_up,
|
||||
sticky_top: this.propTop + (new_style?.tabs_margin?.margin_top || 0),
|
||||
article_tabs: new_data,
|
||||
style_container: common_styles_computer(common_style),
|
||||
style_img_container: common_img_computer(common_style, this.propIndex),
|
||||
tabs_style: new_tabs_style,
|
||||
article_margin_top: 'margin-top:' + (new_style?.article_content_spacing || 0) * 2 + 'rpx',
|
||||
tabs_sliding_fixed_bg: gradient_computer(tabs_data),
|
||||
tabs_container: gradient_computer(tabs_data) + radius_computer(tabs_radius) + margin_computer(new_style?.tabs_margin || old_margin) + border_computer(tabs_content) + box_shadow_computer(tabs_content) + 'overflow: hidden;',
|
||||
tabs_img_container: background_computer(tabs_data) + padding_computer(tabs_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
article_container: gradient_computer(article_content_data) + margin_computer(article_content_margin) + radius_computer(article_content_radius) + box_shadow_computer(article_content) + border_computer(article_content) + 'overflow: hidden;',
|
||||
article_img_container: background_computer(article_content_data) + padding_computer(article_content_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
});
|
||||
},
|
||||
// tabs切换事件
|
||||
tabs_click_event(index) {
|
||||
let new_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
new_data.content.theme = new_data.content.article_theme;
|
||||
new_data.content.data_type = new_data.content.tabs_list[index].data_type;
|
||||
new_data.content.category = new_data.content.tabs_list[index].category;
|
||||
new_data.content.carousel_col = new_data.content.article_carousel_col;
|
||||
new_data.content.data_list = new_data.content.tabs_list[index].data_list;
|
||||
new_data.content.data_auto_list = new_data.content.tabs_list[index].data_auto_list;
|
||||
new_data.content.data_ids = new_data.content.tabs_list[index].data_ids;
|
||||
new_data.content.number = new_data.content.tabs_list[index].number;
|
||||
new_data.content.sort = new_data.content.tabs_list[index].sort;
|
||||
new_data.content.sort_rules = new_data.content.tabs_list[index].sort_rules;
|
||||
new_data.content.field_show = new_data.content.field_show;
|
||||
new_data.content.is_cover = new_data.content.tabs_list[index].is_cover;
|
||||
this.setData({
|
||||
tabs_index: index,
|
||||
article_tabs: new_data,
|
||||
diy_key: Math.random(),
|
||||
});
|
||||
},
|
||||
// 获取商品距离顶部的距离
|
||||
getTop() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.article-tabs-' + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_style = new_data.style || {};
|
||||
this.setData({
|
||||
tabs_top: res.top - (new_style.common_style?.margin_top || 0) + (new_style?.tabs_margin?.margin_top || 0),
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tabs-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
64
components/diy/auxiliary-blank.vue
Normal file
64
components/diy/auxiliary-blank.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view :style="style"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const { height } = this.propValue.content;
|
||||
const { line_color, common_style } = this.propValue.style;
|
||||
this.setData({
|
||||
style: `height: ${height * 2}rpx;background: ${line_color || 'transparent'};`,
|
||||
style_container: common_styles_computer(common_style),
|
||||
style_img_container: common_img_computer(common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.right-0 {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
</style>
|
||||
64
components/diy/auxiliary-line.vue
Normal file
64
components/diy/auxiliary-line.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<!-- 横线 -->
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view :style="style"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
// key
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
// 边框设置
|
||||
let border_content = `border-bottom-style: ${new_content?.styles || 'solid'};`;
|
||||
// 边框颜色设置
|
||||
let border_style = `border-bottom-width: ${new_style.line_width * 2 || 2}rpx; border-bottom-color: ${new_style.line_color || 'rgba(204, 204, 204, 1)'};`;
|
||||
this.setData({
|
||||
style: border_content + border_style,
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
371
components/diy/carousel.vue
Normal file
371
components/diy/carousel.vue
Normal file
@@ -0,0 +1,371 @@
|
||||
<template>
|
||||
<view class="pr" :style="style_container + swiper_bg_style">
|
||||
<view class="pa top-0 wh-auto ht-auto" :style="swiper_bg_img_style"></view>
|
||||
<view class="pr" :style="style_img_container + (!isEmpty(swiper_bg_img_style) ? swiper_bg_img_style_null : '')">
|
||||
<swiper circular="true" :autoplay="form.is_roll == '1'" :interval="form.interval_time * 1000" :display-multiple-items="slides_per_group" :duration="500" :style="{ height: swiper_height }" :previous-margin="previousMargin" :next-margin="nextMargin" @change="slideChange">
|
||||
<block v-if="form.carousel_type == 'card'">
|
||||
<swiper-item v-for="(item, index) in new_list" :key="index">
|
||||
<view class="flex-row align-c wt-auto ht-auto" :data-value="item.carousel_link.page" @tap="url_open">
|
||||
<view class="swiper-item" :style="img_style" :class="['scale-defalt', { 'scale-1': animationData === index }]">
|
||||
<view class="wh-auto ht-auto">
|
||||
<imageEmpty :propImageSrc="item.carousel_img[0]" :propStyle="img_style" :propImgFit="img_fit" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="new_style.video_is_show == '1' && item.carousel_video.length > 0" :class="{ 'x-middle': new_style.video_location == 'center', 'right-0': new_style.video_location == 'flex-end' }" class="video-class pa oh" :style="{'bottom': new_style.video_bottom * 2 + 'rpx'}">
|
||||
<view class="flex-row gap-5 align-c" :style="video_style" :data-value="item.carousel_video" @tap.stop="video_play">
|
||||
<block v-if="new_style.video_type == 'img'">
|
||||
<view class="video_img">
|
||||
<imageEmpty :propImageSrc="new_style.video_img[0]" propImgFit="aspectFill" propErrorStyle="width: 28rpx;height: 28rpx;"></imageEmpty>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<iconfont :name="!isEmpty(new_style.video_icon_class) ? 'icon-' + new_style.video_icon_class : 'icon-bofang'" size="'28rpx'" :color="new_style.video_icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</block>
|
||||
<text v-if="!isEmpty(item.video_title)" :style="{ color: new_style.video_title_color, 'font-size': new_style.video_title_size * 2 + 'rpx', 'text-wrap': 'nowrap' }">{{ item.video_title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</block>
|
||||
<block v-else>
|
||||
<swiper-item v-for="(item, index) in new_list" :key="index">
|
||||
<view class="ht-auto" :style="['oneDragOne', 'twoDragOne'].includes(form.carousel_type) ? 'padding-right:' + new_style.image_spacing * 2 + 'rpx;' : ''" :data-value="item.carousel_link.page" @tap="url_open">
|
||||
<view class="wh-auto ht-auto pr" :style="img_style">
|
||||
<imageEmpty :propImageSrc="item.carousel_img[0]" :propStyle="img_style" :propImgFit="img_fit" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-if="new_style.video_is_show == '1' && item.carousel_video.length > 0" :class="{ 'x-middle': new_style.video_location == 'center', 'right-0': new_style.video_location == 'flex-end' }" class="video-class pa oh" :style="{'bottom': new_style.video_bottom * 2 + 'rpx'}">
|
||||
<view class="flex-row gap-5 align-c" :style="video_style" :data-value="item.carousel_video" @tap.stop="video_play">
|
||||
<block v-if="new_style.video_type == 'img'">
|
||||
<view class="video_img">
|
||||
<imageEmpty :propImageSrc="new_style.video_img[0]" propImgFit="aspectFill" propErrorStyle="width: 28rpx;height: 28rpx;"></imageEmpty>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<iconfont :name="!isEmpty(new_style.video_icon_class) ? 'icon-' + new_style.video_icon_class : 'icon-bofang'" size="'28rpx'" :color="new_style.video_icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</block>
|
||||
<text v-if="!isEmpty(item.video_title)" :style="{ color: new_style.video_title_color, 'font-size': new_style.video_title_size * 2 + 'rpx', 'text-wrap': 'nowrap' }">{{ item.video_title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</block>
|
||||
</swiper>
|
||||
<view v-if="new_style.is_show == '1'" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
|
||||
<template v-if="new_style.indicator_style == 'num'">
|
||||
<view :style="indicator_style" class="dot-item">
|
||||
<text :style="{ color: new_style.actived_color }">{{ actived_index + 1 }}</text>
|
||||
<text>/{{ form.carousel_list.length }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index2) in form.carousel_list" :key="index2" :style="indicator_style + (actived_index == index2 ? 'background:' + new_style.actived_color : '')" class="dot-item" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, radius_computer, isEmpty, gradient_computer, padding_computer, get_indicator_location_style, get_indicator_style, background_computer } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propIsCommon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propOuterContainerPadding: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
// 通用样式显示
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
// 图片的设置
|
||||
img_style: '',
|
||||
// 指示器的样式
|
||||
indicator_style: '',
|
||||
seat_list: [],
|
||||
new_list: [],
|
||||
// 指示器选中的位置
|
||||
actived_index: 0,
|
||||
interval_types: '',
|
||||
img_fit: '',
|
||||
dot_style: '',
|
||||
video_style: '',
|
||||
popup_width: '0rpx',
|
||||
popup_height: '0rpx',
|
||||
// 样式二的处理
|
||||
animation: '',
|
||||
animationData: 0,
|
||||
previousMargin: '0rpx',
|
||||
nextMargin: '0rpx',
|
||||
slides_per_group: 1,
|
||||
// hackReset: true,
|
||||
// 轮播图的高度
|
||||
swiper_height: 50,
|
||||
// 轮播时的背景样式
|
||||
swiper_bg_style: '',
|
||||
swiper_bg_img_style: '',
|
||||
swiper_bg_img_style_null: `background-image: url('')`
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
// 获取当前手机的宽度
|
||||
const { windowWidth } = uni.getSystemInfoSync();
|
||||
// 将80%的宽度分成16份
|
||||
const block = (windowWidth * 0.8) / 16;
|
||||
|
||||
const { common_style, actived_color } = new_style;
|
||||
// scaleToFill 对应 fill aspectFit 对应 contain aspectFill 对应 cover
|
||||
let fit = '';
|
||||
if (new_form.img_fit == 'contain') {
|
||||
fit = 'aspectFit';
|
||||
} else if (new_form.img_fit == 'fill') {
|
||||
fit = 'scaleToFill';
|
||||
} else if (new_form.img_fit == 'cover') {
|
||||
fit = 'aspectFill';
|
||||
}
|
||||
const { margin_left, margin_right, padding_left, padding_right } = new_style.common_style;
|
||||
const width = sys_width - margin_left - margin_right - padding_left - padding_right - this.propOuterContainerPadding;
|
||||
const scale = width / 390;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
seat_list: this.get_seat_list(new_form),
|
||||
new_list: new_form.carousel_list.concat(this.get_seat_list(new_form)),
|
||||
popup_width: block * 16 * 2 + 'rpx', // 视频的宽度,依照16:9比例来算
|
||||
popup_height: block * 9 * 2 + 'rpx', // 视频的高度
|
||||
style_container: this.propIsCommon ? common_styles_computer(common_style) : '', // 公共样式显示
|
||||
style_img_container: this.propIsCommon ? common_img_computer(common_style, this.propIndex) : '', // 公共样式显示
|
||||
img_style: radius_computer(new_style), // 图片的设置
|
||||
indicator_style: get_indicator_style(new_style), // 指示器的样式
|
||||
indicator_location_style: get_indicator_location_style(new_style),
|
||||
dot_style: `bottom: ${ new_style.indicator_bottom * scale }px;`, // 指示器位置
|
||||
img_fit: fit, // 图片风格 默认为aspectFill
|
||||
video_style: this.get_video_style(new_style), // 视频播放按钮显示逻辑
|
||||
swiper_height: new_form.height * scale + 'px', // 轮播图高度
|
||||
swiper_bg_style: this.get_swiper_bg_style(new_form, 0),
|
||||
swiper_bg_img_style: this.get_swiper_bg_img_style(new_form, 0),
|
||||
});
|
||||
// 风格二显示逻辑
|
||||
if (new_form.carousel_type == 'card') {
|
||||
// this.$nextTick(() => {
|
||||
this.setData({
|
||||
previousMargin: '41px',
|
||||
nextMargin: '41px',
|
||||
animationData: 0,
|
||||
});
|
||||
// });
|
||||
} else if (new_form.carousel_type != 'inherit') {
|
||||
// 风格三,四显示逻辑
|
||||
// this.$nextTick(() => {
|
||||
this.setData({
|
||||
nextMargin: '50px',
|
||||
slides_per_group: new_form.carousel_type == 'twoDragOne' ? 2 : 1,
|
||||
});
|
||||
// });
|
||||
}
|
||||
},
|
||||
get_swiper_bg_style(form, actived_index) {
|
||||
if (!this.propIsCommon) {
|
||||
return '';
|
||||
}
|
||||
const style = form?.carousel_list?.[actived_index]?.style;
|
||||
if (style && !isEmpty(style.color_list)) {
|
||||
const color_list = style.color_list;
|
||||
const list = color_list.filter((item) => !isEmpty(item.color));
|
||||
if (list.length > 0) {
|
||||
try {
|
||||
return gradient_computer(style);
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
get_swiper_bg_img_style(form, actived_index) {
|
||||
if (!this.propIsCommon) {
|
||||
return '';
|
||||
}
|
||||
const { carousel_img, style = {} } = form?.carousel_list[actived_index] || {};
|
||||
// 如果是自定义的图片 判断图片是否存在
|
||||
if (!isEmpty(carousel_img) && style?.background_type == 'carousel') {
|
||||
// 如果是使用轮播图,判断轮播图是否存在
|
||||
const data = {
|
||||
background_img: carousel_img,
|
||||
background_img_style: style?.background_img_style || '2',
|
||||
}
|
||||
return background_computer(data) + (style.is_background_img_blur == '1' ? `filter: blur(14px);opacity: 0.6;` : '');
|
||||
} else if (!isEmpty(style?.background_img)) {
|
||||
return background_computer(style) + (style.is_background_img_blur == '1' ? `filter: blur(14px);opacity: 0.6;` : '');
|
||||
}
|
||||
return '';
|
||||
},
|
||||
get_seat_list(form) {
|
||||
if (form.carousel_list.length > 3) {
|
||||
return [];
|
||||
} else {
|
||||
let seat_list = [];
|
||||
const list = JSON.parse(JSON.stringify(form.carousel_list));
|
||||
switch (list.length) {
|
||||
case 1:
|
||||
seat_list = [...list, ...list, ...list];
|
||||
break;
|
||||
case 2:
|
||||
seat_list.push(...list);
|
||||
break;
|
||||
case 3:
|
||||
seat_list.push(...list);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return seat_list;
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
let actived_index = e.detail.current;
|
||||
if (e.detail.current > this.form.carousel_list.length - 1) {
|
||||
const seat_length = this.seat_list.length;
|
||||
if (this.form.carousel_list.length > 1) {
|
||||
actived_index = actived_index - seat_length;
|
||||
} else {
|
||||
actived_index = 0;
|
||||
}
|
||||
}
|
||||
if (!this.propIsCommon) {
|
||||
this.$emit('slideChange', actived_index);
|
||||
}
|
||||
this.setData({
|
||||
animationData: e.detail.current,
|
||||
actived_index: actived_index,
|
||||
swiper_bg_style: this.get_swiper_bg_style(this.form, actived_index),
|
||||
swiper_bg_img_style: this.get_swiper_bg_img_style(this.form, actived_index),
|
||||
});
|
||||
},
|
||||
get_video_style(new_style) {
|
||||
const { video_radius, video_color_list, video_direction, video_title_color, video_padding } = new_style;
|
||||
let style = ``;
|
||||
if (!isEmpty(video_radius)) {
|
||||
style += radius_computer(video_radius);
|
||||
}
|
||||
const data = {
|
||||
color_list: video_color_list,
|
||||
direction: video_direction,
|
||||
};
|
||||
style += gradient_computer(data) + padding_computer(video_padding) + `color: ${video_title_color};box-sizing: border-box;`;
|
||||
return style;
|
||||
},
|
||||
video_play(e) {
|
||||
const list = e.currentTarget.dataset.value;
|
||||
if (!isEmpty(list)) {
|
||||
this.$emit('onVideoPlay', list[0].url, this.popup_width, this.popup_height);
|
||||
}
|
||||
},
|
||||
url_open(link) {
|
||||
app.globalData.url_event(link);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dot-center {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.dot-right {
|
||||
right: 0;
|
||||
}
|
||||
.dot {
|
||||
z-index: 1;
|
||||
padding-left: 20rpx;
|
||||
padding-right: 20rpx;
|
||||
.dot-item {
|
||||
margin: 0 6rpx;
|
||||
}
|
||||
}
|
||||
.swiper-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 90%;
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scale-defalt {
|
||||
position: relative;
|
||||
border-radius: 20rpx;
|
||||
transform: scale(1);
|
||||
transition: -webkit-transform 400ms linear, transform 400ms linear;
|
||||
transform-origin: 50% 50% 0px;
|
||||
&.scale-1 {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
.video_img {
|
||||
max-width: 120rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
.video-class {
|
||||
max-width: 100%;
|
||||
padding-right: 20rpx;
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
.x-middle {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
</style>
|
||||
1013
components/diy/coupon.vue
Normal file
1013
components/diy/coupon.vue
Normal file
File diff suppressed because it is too large
Load Diff
337
components/diy/custom.vue
Normal file
337
components/diy/custom.vue
Normal file
@@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view :style="style_content_container">
|
||||
<view class="w h pr" :style="style_content_img_container">
|
||||
<template v-if="!isEmpty(form.data_source) && form.data_source_is_loop !== '0'">
|
||||
<template v-if="data_source_content_list.length > 0 && form.data_source_direction == 'vertical'">
|
||||
<view class="flex-row flex-wrap" :style="'row-gap:' + new_style.row_gap + 'px;column-gap:' + new_style.column_gap + 'px;'">
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" class="ht-auto" :style="gap_width">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1">
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propFieldList="field_list" :propDataHeight="form.height" :propScale="scale" :propDataIndex="index" :propDataSplitIndex="index1" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else-if="data_source_content_list.length > 0 && ['vertical-scroll', 'horizontal'].includes(form.data_source_direction)" class="oh ht-auto">
|
||||
<swiper class="w flex" circular="true" :vertical="form.data_source_direction != 'horizontal'" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_view" :style="{ width: '100%', height: swiper_height + 'px' }" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in data_source_content_list" :key="index">
|
||||
<view :class="form.data_source_direction != 'horizontal' ? 'ht-auto ' : 'flex-row'" :style="form.data_source_direction == 'horizontal' ? 'column-gap:' + new_style.column_gap + 'px;' : ''">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1" class="wh-auto ht-auto" :style="style_chunk_container + swiper_width + (form.data_source_direction == 'horizontal' ? gap_width : 'margin-bottom:' + content_outer_spacing_magin)">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propFieldList="field_list" :propScale="scale" :propDataIndex="index" :propDataSplitIndex="index1" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-if="new_style.is_show == '1' && data_source_content_list.length > 1" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
|
||||
<block v-if="new_style.indicator_style == 'num'">
|
||||
<view :style="indicator_style" class="dot-item">
|
||||
<text :style="{ color: new_style.actived_color }">{{ actived_index + 1 }}</text>
|
||||
<text>/{{ data_source_content_list.length }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" :style="indicator_style + (actived_index == index ? 'background:' + new_style.actived_color : '')" class="dot-item" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<template v-else>
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propConfigLoop="form.data_source_is_loop || '1'" :propFieldList="field_list" :propDataHeight="form.height" :propScale="scale" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="!isEmpty(form.data_source) && form.data_source_is_loop == '0'">
|
||||
<view class="h" :style="style_chunk_container">
|
||||
<view class="w h oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propSourceList="{}" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propFieldList="field_list" :propDataHeight="form.height" :propScale="scale" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propConfigLoop="form.data_source_is_loop || '1'" :propFieldList="field_list" :propDataHeight="form.height" :propScale="scale" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer, percentage_count, isEmpty, get_indicator_style, get_indicator_location_style, border_width } from '@/common/js/common/common.js';
|
||||
import dataRendering from '@/components/diy/modules/custom/data-rendering.vue';
|
||||
const app = getApp();
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
|
||||
export default {
|
||||
components: {
|
||||
dataRendering
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propIsCommonStyle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propOuterContainerPadding: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
scale: 1,
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
div_width: 0,
|
||||
div_height: 0,
|
||||
custom_list_length: 0,
|
||||
source_list: {
|
||||
// 存放手动输入的id
|
||||
data_ids: [],
|
||||
// 手动输入
|
||||
data_list: [],
|
||||
// 自动
|
||||
data_auto_list: [],
|
||||
},
|
||||
data_source_content_list: [],
|
||||
data_source: '',
|
||||
// 内容样式
|
||||
style_content_container: '',
|
||||
style_content_img_container: '',
|
||||
// 数据样式
|
||||
style_chunk_container: '',
|
||||
style_chunk_img_container: '',
|
||||
// 指示器选中的下标
|
||||
actived_index: 0,
|
||||
// 轮播高度
|
||||
swiper_height: 0,
|
||||
swiper_width: 'width: 100%;',
|
||||
// 指示器样式
|
||||
indicator_location_style: '',
|
||||
indicator_style: '',
|
||||
slides_per_view: 1,
|
||||
show_data: { data_key: 'id', data_name: 'name' },
|
||||
old_data_style: {
|
||||
color_list: [{ color: 'rgb(244, 252, 255)', color_percentage: undefined }],
|
||||
direction: '180deg',
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
radius: 0,
|
||||
radius_top_left: 0,
|
||||
radius_top_right: 0,
|
||||
radius_bottom_left: 0,
|
||||
radius_bottom_right: 0,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
},
|
||||
content_outer_spacing_magin: '0rpx',
|
||||
gap_width: '',
|
||||
field_list: [],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
percentage_count,
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
// 不包含新创建的数组时,将历史数据放到手动添加数组中
|
||||
if (!Object.keys(new_form.data_source_content).includes('data_auto_list') && !Object.keys(new_form.data_source_content).includes('data_list')) {
|
||||
//深拷贝一下,保留历史数据
|
||||
const data = JSON.parse(JSON.stringify(new_form.data_source_content));
|
||||
new_form.data_source_content = this.source_list;
|
||||
// 如果老数组中有数据,将数据放到新数组中
|
||||
if (!isEmpty(data)) {
|
||||
new_form.data_source_content.data_list = [ data ];
|
||||
}
|
||||
}
|
||||
// 数据来源的内容
|
||||
let list = [];
|
||||
if (new_form.is_custom_data == '1') {
|
||||
if (Number(new_form.data_source_content.data_type) === 0) {
|
||||
list = new_form.data_source_content?.data_list || [];
|
||||
} else {
|
||||
list = !isEmpty(new_form.data_source_content) ?
|
||||
new_form.data_source_content.data_auto_list.map(item => ({
|
||||
id: Math.random(),
|
||||
new_cover: [],
|
||||
new_title: '',
|
||||
data: item,
|
||||
})) : [];
|
||||
}
|
||||
} else {
|
||||
list = new_form.data_source_content?.data_list || [];
|
||||
}
|
||||
// 数组处理
|
||||
const new_list = list.length > 0 ? this.get_list(list, new_form, new_style) : [];
|
||||
// 初始化数据
|
||||
const { common_style, data_content_style, data_style } = new_style;
|
||||
// 外层左右间距
|
||||
const outer_spacing = (common_style?.margin_left || 0) + (common_style?.margin_right || 0) + (common_style?.padding_left || 0) + (common_style?.padding_right || 0) + border_width(common_style);
|
||||
// 内容左右间距
|
||||
const content_spacing = (data_content_style?.margin_left || 0) + (data_content_style?.margin_right || 0) + (data_content_style?.padding_left || 0) + (data_content_style?.padding_right || 0) + border_width(data_content_style);
|
||||
// 数据左右间距
|
||||
const internal_spacing = (data_style?.margin_left || 0) + (data_style?.margin_right || 0) + (data_style?.padding_left || 0) + (data_style?.padding_right || 0) + border_width(data_style);
|
||||
// 一行显示的数量
|
||||
const carousel_col = Number(new_form.data_source_carousel_col);
|
||||
// 数据间距
|
||||
const data_spacing = ['vertical', 'horizontal'].includes(new_form.data_source_direction) ? new_style.column_gap * (carousel_col - 1) : 0;
|
||||
// 自定义组件宽度
|
||||
const width = sys_width - outer_spacing - content_spacing - internal_spacing - data_spacing - this.propOuterContainerPadding;
|
||||
const new_data_style = !isEmpty(new_style.data_style) ? new_style.data_style : this.old_data_style;
|
||||
const new_data_content_style = !isEmpty(new_style.data_content_style)? new_style.data_content_style : this.old_data_style;
|
||||
// 判断是平移还是整屏滚动
|
||||
const { padding_top = 0, padding_bottom = 0, margin_bottom = 0, margin_top = 0 } = new_data_style;
|
||||
let swiper_height = 0;
|
||||
const scale_number = width / 390;
|
||||
const new_scale = scale_number > 0 ? scale_number : 0;
|
||||
// 间距
|
||||
const space_between = new_form.data_source_direction == 'horizontal' ? new_style.column_gap : new_style.row_gap;
|
||||
let col = Number(new_form.data_source_carousel_col);
|
||||
// 轮播图高度控制
|
||||
if (new_form.data_source_direction == 'horizontal') {
|
||||
swiper_height = new_form.height * new_scale + padding_top + padding_bottom + margin_bottom + margin_top;
|
||||
} else {
|
||||
// 商品数量大于列数的时候,高度是列数,否则是当前的数量
|
||||
col = new_list.length > carousel_col ? carousel_col : new_list.length;
|
||||
swiper_height = (new_form.height * new_scale + padding_top + padding_bottom + margin_bottom + margin_top) * col + ((Number(new_form.data_source_carousel_col) - 1) * space_between);
|
||||
}
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.column_gap * (carousel_col - 1)) / carousel_col;
|
||||
// 横向的时候,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
const swiper_width = (new_form.data_source_direction == 'horizontal' && new_style.rolling_fashion != 'translation') ? `width: ${ 100 / carousel_col }%;`: 'width: 100%;';
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
div_width: width,
|
||||
scale: new_scale,
|
||||
custom_list_length: new_form.custom_list.length - 1,
|
||||
style_container: this.propIsCommonStyle ? common_styles_computer(new_style.common_style) + 'box-sizing: border-box;' : '', // 用于样式显示
|
||||
style_img_container: this.propIsCommonStyle ? common_img_computer(new_style.common_style, this.propIndex) : '',
|
||||
style_content_container: common_styles_computer(new_data_content_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_content_img_container: common_img_computer(new_data_content_style),
|
||||
style_chunk_container: common_styles_computer(new_data_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_chunk_img_container: common_img_computer(new_data_style),
|
||||
style_chunk_width: width,
|
||||
div_height: new_form.height,
|
||||
data_source_content_list: new_list,
|
||||
data_source: !isEmpty(new_form.data_source)? new_form.data_source : '',
|
||||
indicator_style: get_indicator_style(new_style), // 指示器的样式
|
||||
indicator_location_style: get_indicator_location_style(new_style),
|
||||
swiper_height: swiper_height,
|
||||
swiper_width: swiper_width,
|
||||
content_outer_spacing_magin: space_between + 'px',
|
||||
gap_width: `width: calc(${100 / carousel_col}% - ${gap}px);`,
|
||||
slides_per_view: new_style.rolling_fashion == 'translation' ? (new_form.data_source_direction != 'horizontal' ? col : new_form.data_source_carousel_col ) : 1,
|
||||
show_data: new_form?.show_data || { data_key: 'id', data_name: 'name' },
|
||||
field_list: new_form?.field_list || [],
|
||||
});
|
||||
},
|
||||
get_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation' && form.data_source_direction != 'vertical') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.data_source_carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
this.setData({
|
||||
actived_index: e.detail.current,
|
||||
});
|
||||
},
|
||||
url_event(e, index, split_index) {
|
||||
if (this.data_source == 'goods' && this.data_source_content_list.length > 0) {
|
||||
const list = this.data_source_content_list[index];
|
||||
if (!isEmpty(list) && !isEmpty(list.split_list[split_index])) {
|
||||
const new_list = list.split_list[split_index];
|
||||
if (!isEmpty(new_list)) {
|
||||
// 缓存商品数据
|
||||
app.globalData.goods_data_cache_handle(new_list.data.id, new_list.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
app.globalData.url_open(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
434
components/diy/data-magic.vue
Normal file
434
components/diy/data-magic.vue
Normal file
@@ -0,0 +1,434 @@
|
||||
<template>
|
||||
<view class="img-magic" :style="'height:' + container_size + ';' + style_container">
|
||||
<view class="magic-container w h pr" :style="style_img_container">
|
||||
<view class="pr" :style="'width:calc(100% + ' + outer_spacing + ');height:calc(100% + ' + outer_spacing + ');margin:-' + spacing + ';'">
|
||||
<!-- 风格9 -->
|
||||
<template v-if="form.style_actived == 7">
|
||||
<view class="flex-row align-c jc-c style-size flex-wrap">
|
||||
<view v-for="(item, index) in data_magic_list" :key="index" :style="'margin:' + spacing + ';' + ([0, 1].includes(index) ? 'width:calc(50% - ' + outer_spacing + ');height:calc(50% - ' + outer_spacing + ')' : 'width:calc((100% / 3) - ' + outer_spacing + ');height:calc(50% - ' + outer_spacing + ')')" class="style9">
|
||||
<view class="w h flex-row" :style="item.data_style.background_style + content_radius">
|
||||
<view class="re flex-1 oh" :style="item.data_style.background_img_style">
|
||||
<template v-if="item.data_content.data_type == 'goods'">
|
||||
<view class="w h flex-col" :style="'gap:'+ item.data_style.title_data_gap * 2 + 'rpx;'">
|
||||
<view v-if="(!isEmpty(item.data_content.heading_title) || !isEmpty(item.data_content.subtitle)) && [0, 1].includes(index)" :class="'tl' + (item.data_style.title_line == '1' ? ' flex-row align-c' : ' flex-col')" :style="'gap:' + item.data_style.title_gap * 2 + 'rpx;'">
|
||||
<template v-if="item.data_content.heading_title_type && item.data_content.heading_title_type == 'image'">
|
||||
<view v-if="item.data_content.heading_title_img.length > 0" class="re oh" :style="'width:100%;height:' + (!isEmpty(item.data_style.heading_img_height) ? item.data_style.heading_img_height * magic_scale : 0) + 'px'">
|
||||
<image :src="item.data_content.heading_title_img[0].url" class="ht-auto max-w" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="ma-0 w text-word-break text-line-1 flex-basis-shrink" :style="item.data_style.heading_style">{{ item.data_content.heading_title || '' }}</view>
|
||||
</template>
|
||||
<template v-if="item.data_content.subtitle_title_type && item.data_content.subtitle_title_type == 'image'">
|
||||
<view v-if="item.data_content.subtitle_title_img.length > 0" class="re oh" :style="'width:100%;height:' + (!isEmpty(item.data_style.subtitle_img_height) ? item.data_style.subtitle_img_height * magic_scale : 0) + 'px'">
|
||||
<image :src="item.data_content.subtitle_title_img[0].url" class="ht-auto max-w" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="ma-0 w text-word-break text-line-1 flex-basis-shrink" :style="item.data_style.subtitle_style">{{ item.data_content.subtitle || '' }}</view>
|
||||
</template>
|
||||
</view>
|
||||
<view class="w h flex-1 oh flex-row">
|
||||
<magic-carousel class="flex-1" :propKey="propKey + index" :propValue="item" :propGoodStyle="item.data_style" :propActived="form.style_actived" propType="product" :propDataIndex="index" @onCarouselChange="carousel_change"></magic-carousel>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="item.data_content.data_type == 'images'">
|
||||
<view class="w h flex-1 oh flex-row">
|
||||
<magic-carousel class="flex-1" :propKey="propKey + index" :propValue="item" propType="img" :propActived="form.style_actived" :propDataIndex="index" @onCarouselChange="carousel_change"></magic-carousel>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="item.data_content.data_type == 'custom'">
|
||||
<customIndex :propKey="propKey + index" :propValue="item" :propMagicScale="magic_scale" :propDataSpacing="new_style.image_spacing" :propDataIndex="index" @onCarouselChange="carousel_change"></customIndex>
|
||||
</template>
|
||||
<template v-else>
|
||||
<videoIndex :propKey="propKey + index" :propValue="item.data_content" :propDataStyle="item.data_style"></videoIndex>
|
||||
</template>
|
||||
<view v-if="item.data_style.is_show == '1' && item.data_content.list.length > 1" :class="['left', 'right'].includes(item.data_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="item.data_style.indicator_location_style">
|
||||
<template v-if="item.data_style.indicator_style == 'num'">
|
||||
<view :style="item.data_style.indicator_styles" class="dot-item">
|
||||
<text class="num-active" :style="{ color: item.data_style.actived_color }">{{ item.actived_index + 1 }}</text
|
||||
><text>/{{ item.data_content.list.length }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item3, index3) in item.data_content.list" :key="index3" :style="item.data_style.indicator_styles + style_actived_color(item, index3)" class="dot-item" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index) in data_magic_list" :key="index" class="cr-main cube-selected" :style="selected_style(item) + ';margin:' + spacing + ';'">
|
||||
<view class="w h flex-row" :style="item.data_style.background_style + content_radius">
|
||||
<view class="re flex-1 oh" :style="item.data_style.background_img_style">
|
||||
<template v-if="item.data_content.data_type == 'goods'">
|
||||
<view class="w h flex-col" :style="'gap:'+ item.data_style.title_data_gap * 2 + 'rpx;'">
|
||||
<view v-if="!isEmpty(item.data_content.heading_title) || !isEmpty(item.data_content.subtitle)" :class="'tl' + (item.data_style.title_line == '1' ? ' flex-row align-c' : ' flex-col')" :style="'gap:' + item.data_style.title_gap * 2 + 'rpx;'">
|
||||
<template v-if="item.data_content.heading_title_type && item.data_content.heading_title_type == 'image'">
|
||||
<view v-if="item.data_content.heading_title_img.length > 0" class="re oh" :style="'width:100%;height:' + (!isEmpty(item.data_style.heading_img_height) ? item.data_style.heading_img_height * magic_scale : 0) + 'px'">
|
||||
<image :src="item.data_content.heading_title_img[0].url" class="ht-auto max-w" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="ma-0 w text-word-break text-line-1 flex-basis-shrink" :style="item.data_style.heading_style">{{ item.data_content.heading_title || '' }}</view>
|
||||
</template>
|
||||
<template v-if="item.data_content.subtitle_title_type && item.data_content.subtitle_title_type == 'image'">
|
||||
<view v-if="item.data_content.subtitle_title_img.length > 0" class="re oh" :style="'width:100%;height:' + (!isEmpty(item.data_style.subtitle_img_height) ? item.data_style.subtitle_img_height * magic_scale : 0) + 'px'">
|
||||
<image :src="item.data_content.subtitle_title_img[0].url" class="ht-auto max-w" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="ma-0 w text-word-break text-line-1 flex-basis-shrink" :style="item.data_style.subtitle_style">{{ item.data_content.subtitle || '' }}</view>
|
||||
</template>
|
||||
</view>
|
||||
<view class="w h oh flex-row">
|
||||
<magic-carousel class="flex-1" :propKey="propKey + index" :propValue="item" :propGoodStyle="item.data_style" propType="product" :propActived="form.style_actived" :propDataIndex="index" @onCarouselChange="carousel_change"></magic-carousel>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="item.data_content.data_type == 'images'">
|
||||
<view class="w h oh flex-row">
|
||||
<magic-carousel class="flex-1" :propKey="propKey + index" :propValue="item" propType="img" :propActived="form.style_actived" :propDataIndex="index" @onCarouselChange="carousel_change"></magic-carousel>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="item.data_content.data_type == 'custom'">
|
||||
<customIndex :propKey="propKey + index" :propValue="item" :propMagicScale="magic_scale" :propDataSpacing="new_style.image_spacing" :propDataIndex="index" @onCarouselChange="carousel_change"></customIndex>
|
||||
</template>
|
||||
<template v-else>
|
||||
<videoIndex :propKey="propKey + index" :propValue="item.data_content" :propDataStyle="item.data_style"></videoIndex>
|
||||
</template>
|
||||
<view v-if="item.data_style.is_show == '1' && item.data_content.list.length > 1" :class="['left', 'right'].includes(item.data_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="item.data_style.indicator_location_style">
|
||||
<template v-if="item.data_style.indicator_style == 'num'">
|
||||
<view :style="item.data_style.indicator_styles" class="dot-item">
|
||||
<text class="num-active" :style="{ color: item.data_style.actived_color }">{{ item.actived_index + 1 }}</text>
|
||||
<text>/{{ item.data_content.list.length }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item3, index3) in item.data_content.list" :key="index3" :style="item.data_style.indicator_styles + style_actived_color(item, index3)" class="dot-item" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import magicCarousel from '@/components/diy/modules/data-magic/magic-carousel.vue';
|
||||
import customIndex from '@/components/diy/modules/data-magic/custom/index.vue';
|
||||
import videoIndex from '@/components/diy/modules/data-magic/video/index.vue';
|
||||
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, radius_computer, percentage_count, isEmpty, padding_computer, margin_computer, old_border_and_box_shadow, old_margin, old_padding, box_shadow_computer, border_computer, get_indicator_location_style, get_indicator_style, border_width } from '@/common/js/common/common.js';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
magicCarousel,
|
||||
customIndex,
|
||||
videoIndex
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propOuterContainerPadding: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
outer_spacing: '',
|
||||
// 图片间距设置
|
||||
spacing: '',
|
||||
// 内容圆角设置
|
||||
content_radius: '',
|
||||
// 图片圆角设置
|
||||
// content_img_radius: '',
|
||||
data_magic_list: [],
|
||||
cubeCellWidth: 0,
|
||||
container_size: 0,
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
div_width: 0,
|
||||
magic_scale: 1,
|
||||
// is_unlimited_size: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 根据当前页面大小计算成百分比
|
||||
selected_style() {
|
||||
return (item) => {
|
||||
return `overflow: hidden;width: calc(${this.percentage(this.getSelectedWidth(item))} - ${this.outer_spacing} ); height: calc(${this.percentage(this.getSelectedHeight(item))} - ${this.outer_spacing} ); top: ${this.percentage(this.getSelectedTop(item))}; left: ${this.percentage(this.getSelectedLeft(item))};`;
|
||||
};
|
||||
},
|
||||
style_actived_color() {
|
||||
return (item, index) => {
|
||||
return item.actived_index == index ? `background: ${item.data_style.actived_color};` : '';
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
const container_height = !isEmpty(new_form.container_height) ? new_form.container_height : sys_width;
|
||||
const density = !isEmpty(new_form.magic_cube_density) ? new_form.magic_cube_density : 4;
|
||||
const { margin_left, margin_right } = new_style.common_style;
|
||||
const width = sys_width - margin_left - margin_right - border_width(new_style.common_style) - this.propOuterContainerPadding;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
outer_spacing: new_style.image_spacing * 2 + 'rpx',
|
||||
spacing: new_style.image_spacing + 'rpx',
|
||||
content_radius: radius_computer(new_style.data_radius),
|
||||
// content_img_radius: radius_computer(new_style.img_radius),
|
||||
data_magic_list: this.get_data_magic_list(new_form.data_magic_list, new_style),
|
||||
style_container: common_styles_computer(new_style.common_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
magic_scale: width / 390,
|
||||
div_width: sys_width,
|
||||
cubeCellWidth: sys_width / density,
|
||||
container_size: container_height * (width / 390) + 'px',
|
||||
});
|
||||
},
|
||||
get_data_magic_list(data, new_style) {
|
||||
data.forEach((item) => {
|
||||
const data_content = item.data_content;
|
||||
const data_style = item.data_style;
|
||||
item.actived_index = 0;
|
||||
// 指示器样式
|
||||
data_style.indicator_styles = get_indicator_style(data_style);
|
||||
data_style.indicator_location_style = get_indicator_location_style(data_style);
|
||||
// 获取当前的margin
|
||||
const chunk_margin = data_style?.chunk_margin || old_margin;
|
||||
// 计算左右间距
|
||||
const left_right_width_margin = (chunk_margin?.margin_left || 0) + (chunk_margin?.margin_right || 0);
|
||||
// 计算上下间距
|
||||
const top_bottom_height_margin = (chunk_margin?.margin_top || 0) + (chunk_margin?.margin_bottom || 0);
|
||||
data_style.background_style = gradient_computer(data_style) + margin_computer(data_style?.chunk_margin || old_margin) + `width: calc(100% - ${ left_right_width_margin }px);height:calc(100% - ${ top_bottom_height_margin }px);` + box_shadow_computer(data_style?.data_common_style || old_border_and_box_shadow) + border_computer(data_style?.data_common_style || old_border_and_box_shadow);
|
||||
data_style.background_img_style = background_computer(data_style) + padding_computer(data_style?.chunk_padding || old_padding);
|
||||
// 商品价格处理
|
||||
data_style.goods_price_symbol_style = this.goods_trends_config(data_style, 'price_symbol');
|
||||
data_style.goods_price_unit_style = this.goods_trends_config(data_style, 'price_unit');
|
||||
|
||||
let fit = '';
|
||||
if (data_content.img_fit == 'contain') {
|
||||
fit = 'aspectFit';
|
||||
} else if (data_content.img_fit =='fill') {
|
||||
fit = 'scaleToFill';
|
||||
} else if (data_content.img_fit == 'cover') {
|
||||
fit = 'aspectFill';
|
||||
}
|
||||
data_content.fit = fit;
|
||||
// 商品名称和价格样式
|
||||
data_style.goods_title_style = this.goods_trends_config(data_style, 'title') + `line-height: ${ (item.data_style.goods_title_size + 3) * 2 }rpx;height: ${ (item.data_style.goods_title_size + 3) * 2 }rpx;`;
|
||||
data_style.goods_price_style = this.goods_trends_config(data_style, 'price') + `line-height: ${ item.data_style.goods_price_size * 2 }rpx;height: ${ (item.data_style.goods_title_size + 3) * 2 }rpx;`;
|
||||
const radius = !isEmpty(data_style.img_radius) ? data_style.img_radius : { radius: 4, radius_top_left: 4, radius_top_right: 4, radius_bottom_left: 4, radius_bottom_right: 4 };
|
||||
data_style.get_img_radius = radius_computer(radius);
|
||||
|
||||
data_style.chunk_padding_data = padding_computer(data_style.chunk_padding) + 'box-sizing: border-box;';
|
||||
data_style.heading_style = this.trends_config(data_style, 'heading');
|
||||
data_style.subtitle_style = this.trends_config(data_style, 'subtitle');
|
||||
|
||||
if (data_content.data_type == 'goods') {
|
||||
data_content.list = this.commodity_list(data_content.goods_list, data_content.goods_num, data_content, data_style);
|
||||
} else if (data_content.data_type == 'custom' && ['vertical-scroll', 'horizontal'].includes(data_content.data_source_direction)) {
|
||||
// 是自定义并且是轮播状态的时候,添加数据
|
||||
const list = this.data_source_content_list(data_content);
|
||||
const carousel_col = data_content?.data_source_carousel_col || 1;
|
||||
const num = new_style.rolling_fashion == 'translation' ? list.length : Math.ceil(list.length / carousel_col);
|
||||
data_content.list = Array(num);
|
||||
} else {
|
||||
data_content.list = data_content.images_list;
|
||||
}
|
||||
});
|
||||
return data;
|
||||
},
|
||||
// 数据来源的内容
|
||||
data_source_content_list(data_content){
|
||||
if (data_content.is_custom_data == '1') {
|
||||
if (Number(data_content.data_source_content.data_type) === 0) {
|
||||
return data_content.data_source_content.data_list;
|
||||
} else {
|
||||
return data_content.data_source_content.data_auto_list.map((item) => ({
|
||||
id: Math.random(),
|
||||
new_cover: [],
|
||||
new_title: '',
|
||||
data: item,
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
return data_content.data_source_content.data_list;
|
||||
}
|
||||
},
|
||||
/*
|
||||
** 组装产品的数据
|
||||
** @param {Array} list 商品列表
|
||||
** @param {Number} num 显示数量
|
||||
** @return {Array}
|
||||
*/
|
||||
commodity_list(list, num, data_content, data_style) {
|
||||
if (list.length > 0) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const goods_list = JSON.parse(JSON.stringify(list)).map((item) => ({
|
||||
...item.data,
|
||||
title: !isEmpty(item.new_title) ? item.new_title : item.data.title,
|
||||
new_cover: item.new_cover,
|
||||
}));
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 如果是滑动,需要根据每行显示的个数来区分来拆分数据 translation 表示的是平移
|
||||
if (data_style.rolling_fashion != 'translation') {
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(goods_list.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({ split_list: goods_list.slice(i * num, (i + 1) * num) });
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
return this.rotation_calculation(goods_list, num, data_content, data_style);
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
rotation_calculation(list, num, data_content, data_style) {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
const goods_outerflex = data_content.goods_outerflex;
|
||||
const rotation_direction = data_style.rotation_direction;
|
||||
// 如果是商品是横排的,轮播也是横排的,就不对商品进行拆分/如果商品是竖排的,轮播也是竖排的,不对商品进行拆分
|
||||
if ((goods_outerflex == 'row' && rotation_direction == 'horizontal') || (goods_outerflex == 'col' && rotation_direction == 'vertical')) {
|
||||
list.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(list.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({ split_list: list.slice(i * num, (i + 1) * num) });
|
||||
}
|
||||
return nav_list;
|
||||
}
|
||||
return nav_list;
|
||||
},
|
||||
getSelectedWidth(item) {
|
||||
return (item.end.x - item.start.x + 1) * this.cubeCellWidth;
|
||||
},
|
||||
//计算选中层的高度。
|
||||
getSelectedHeight(item) {
|
||||
return (item.end.y - item.start.y + 1) * this.cubeCellWidth;
|
||||
},
|
||||
//计算选中层的右边距离。
|
||||
getSelectedTop(item) {
|
||||
return (item.start.y - 1) * this.cubeCellWidth;
|
||||
},
|
||||
//计算选中层的左边距离。
|
||||
getSelectedLeft(item) {
|
||||
return (item.start.x - 1) * this.cubeCellWidth;
|
||||
},
|
||||
// 计算成百分比
|
||||
percentage(num) {
|
||||
return percentage_count(num, this.div_width);
|
||||
},
|
||||
goods_trends_config(style, key) {
|
||||
return this.text_style(style[`goods_${key}_typeface`], style[`goods_${key}_size`], style[`goods_${key}_color`]);
|
||||
},
|
||||
// 根据传递的参数,从对象中取值
|
||||
trends_config(style, key) {
|
||||
return this.text_style(style[`${key}_typeface`], style[`${key}_size`], style[`${key}_color`]);
|
||||
},
|
||||
text_style(typeface, size, color) {
|
||||
return `font-weight:${typeface}; font-size: ${size * 2}rpx; color: ${color};`;
|
||||
},
|
||||
carousel_change(actived_index, index) {
|
||||
if (this.data_magic_list[index]) {
|
||||
this.data_magic_list[index].actived_index = actived_index;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 图片魔方是一个正方形,根据宽度计算高度
|
||||
.img-magic {
|
||||
overflow: hidden;
|
||||
}
|
||||
.cube-selected {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.text-line-1 {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.style-size {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
.style9 {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.dot-center {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.dot-right {
|
||||
right: 0;
|
||||
}
|
||||
.dot {
|
||||
z-index: 3;
|
||||
.dot-item {
|
||||
margin: 0 6rpx;
|
||||
}
|
||||
}
|
||||
.gap-20 {
|
||||
gap: 40rpx;
|
||||
}
|
||||
.w {
|
||||
width: 100%;
|
||||
}
|
||||
.h {
|
||||
height: 100%;
|
||||
}
|
||||
.flex-basis-shrink {
|
||||
flex-basis: content;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
</style>
|
||||
334
components/diy/data-tabs.vue
Normal file
334
components/diy/data-tabs.vue
Normal file
@@ -0,0 +1,334 @@
|
||||
<template>
|
||||
<view class="data-tabs ou" :class="'data-tabs-' + propKey" :style="style_container">
|
||||
<view class="ou" :style="style_img_container">
|
||||
<componentDiyModulesTabsView :propKey="propKey" :propValue="data_tabs" :propIsTop="top_up == '1'" :propTop="sticky_top" :propStyle="tabs_style" :propsTabsContainer="tabs_container" :propsTabsImgContainer="tabs_img_container" :propCustomNavHeight="propIsTabsUseSafeDistance ? (propCustomNavHeight * 2 + 'rpx') : '0rpx'" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" :propTabsBackground="tabs_background" @onTabsTap="tabs_click_event"></componentDiyModulesTabsView>
|
||||
<view :style="data_margin_top">
|
||||
<view :style="data_container">
|
||||
<view :style="data_img_container">
|
||||
<template v-if="tabs_data_type == 'goods'">
|
||||
<view class="oh" :style="data_content_container">
|
||||
<view class="oh" :style="data_content_img_container">
|
||||
<componentGoodsList ref="diy_goods_list" :propKey="diy_key" :propDiyIndex="propDiyIndex" :propValue="tabs_list" :propIsCommonStyle="false" @goods_buy_event="goods_buy_event"></componentGoodsList>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="tabs_data_type == 'article'">
|
||||
<view class="oh" :style="data_content_container">
|
||||
<view class="oh" :style="data_content_img_container">
|
||||
<componentArticleList :propKey="diy_key" :propValue="tabs_list" :propIsCommonStyle="false"></componentArticleList>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="tabs_data_type == 'custom'">
|
||||
<componentCustomList :propKey="diy_key" :propValue="tabs_list" :propOuterContainerPadding="outer_container_width" :propIsCommonStyle="false"></componentCustomList>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, margin_computer, background_computer, gradient_computer, isEmpty, old_border_and_box_shadow, old_margin, old_radius, old_padding, border_computer, box_shadow_computer, radius_computer, get_math } from '@/common/js/common/common.js';
|
||||
import componentDiyModulesTabsView from '@/components/diy/modules/tabs-view';
|
||||
import componentGoodsList from '@/components/diy/goods-list';
|
||||
import componentArticleList from '@/components/diy/article-list';
|
||||
import componentCustomList from '@/components/diy/custom';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
components: {
|
||||
componentDiyModulesTabsView,
|
||||
componentGoodsList,
|
||||
componentArticleList,
|
||||
componentCustomList,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propCustomNavHeight: {
|
||||
type: Number,
|
||||
default: 33,
|
||||
},
|
||||
propScrollTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 顶部导航是否开启沉浸模式
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propDiyIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 选项卡是否使用安全距离
|
||||
propIsTabsUseSafeDistance: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
data_tabs: {},
|
||||
tabs_list: {},
|
||||
// 是否滑动置顶
|
||||
top_up: '0',
|
||||
tabs_top: 0,
|
||||
tabs_background: 'background:transparent',
|
||||
custom_nav_height: 33,
|
||||
diy_key: '',
|
||||
// 选项卡背景设置
|
||||
tabs_container: '',
|
||||
tabs_img_container: '',
|
||||
// 商品区域背景设置
|
||||
data_margin_top: '',
|
||||
data_container: '',
|
||||
data_img_container: '',
|
||||
// #ifdef MP
|
||||
nav_safe_space: bar_height + 5,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
nav_safe_space: bar_height + 7,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
nav_safe_space: bar_height + 0,
|
||||
// #endif
|
||||
tabs_style: '',
|
||||
// 选项卡默认数据
|
||||
tabs_index: 0,
|
||||
sticky_top: 0,
|
||||
tabs_data_type: 'goods',
|
||||
outer_container_width: 0,
|
||||
// 数据样式
|
||||
data_content_container: '',
|
||||
data_content_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
// 滑动固定的背景
|
||||
tabs_sliding_fixed_bg: '',
|
||||
data_content_style: {
|
||||
color_list: [{ color: '', color_percentage: undefined }],
|
||||
direction: '180deg',
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
radius: 0,
|
||||
radius_top_left: 0,
|
||||
radius_top_right: 0,
|
||||
radius_bottom_left: 0,
|
||||
radius_bottom_right: 0,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
// 边框样式
|
||||
border_is_show: '0',
|
||||
border_color: '#FF3F3F',
|
||||
border_style: 'solid',
|
||||
border_size: {
|
||||
padding: 1,
|
||||
padding_top: 1,
|
||||
padding_right: 1,
|
||||
padding_bottom: 1,
|
||||
padding_left: 1,
|
||||
},
|
||||
// 阴影
|
||||
box_shadow_color: '',
|
||||
box_shadow_x: 0,
|
||||
box_shadow_y: 0,
|
||||
box_shadow_blur: 0,
|
||||
box_shadow_spread: 0,
|
||||
}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propScrollTop(newVal) {
|
||||
if (newVal + this.sticky_top + this.custom_nav_height > this.tabs_top + this.nav_safe_space && this.top_up == '1') {
|
||||
let new_style = this.propValue.style || {};
|
||||
let tabs_bg = new_style.common_style.color_list;
|
||||
let new_tabs_background = '';
|
||||
if (tabs_bg.length > 0 && (tabs_bg[0].color || null) != null) {
|
||||
new_tabs_background = gradient_computer(new_style.common_style);
|
||||
}
|
||||
let new_tabs_background_img = background_computer(new_style.common_style);
|
||||
if (new_tabs_background_img.length > 0) {
|
||||
new_tabs_background_img += 'background-position: top left;';
|
||||
}
|
||||
this.tabs_background = (new_tabs_background.length > 0 ? new_tabs_background : 'background:#fff;') + new_tabs_background_img;
|
||||
} else {
|
||||
this.tabs_background = 'background:transparent';
|
||||
}
|
||||
},
|
||||
propTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.setData({
|
||||
diy_key: val,
|
||||
});
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const self = this;
|
||||
setTimeout(() => {
|
||||
self.getTop();
|
||||
});
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// 获取自定义导航栏高度
|
||||
this.setData({
|
||||
custom_nav_height: this.propCustomNavHeight,
|
||||
});
|
||||
// #endif
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_content = new_data.content || {};
|
||||
const new_style = new_data.style || {};
|
||||
// 公共样式
|
||||
const common_style = new_style.common_style;
|
||||
let tabs_style_obj = {
|
||||
padding_top: (common_style.padding_top - this.propCustomNavHeight) < 0 ? 0 : common_style.padding_top - this.propCustomNavHeight,
|
||||
padding_left: common_style.padding_left,
|
||||
padding_right: common_style.padding_right,
|
||||
};
|
||||
let new_tabs_style = padding_computer(tabs_style_obj) + `position:relative;left: -${tabs_style_obj.padding_left * 2}rpx;right: -${tabs_style_obj.padding_right * 2}rpx;width:100%;`;
|
||||
// 如果是历史数据的话,就执行默认添加下边距
|
||||
if (isEmpty(new_style.tabs_padding)) {
|
||||
new_tabs_style += 'padding-bottom: 20rpx;';
|
||||
}
|
||||
|
||||
const { tabs_bg_color_list = [], tabs_bg_direction = '', tabs_bg_background_img_style = '', tabs_bg_background_img = [], tabs_radius = old_radius, tabs_padding = old_padding, data_content_color_list = [], data_content_direction = '', data_content_background_img_style = '', data_content_background_img = [], data_content_margin = old_margin, data_content_padding = old_padding, data_content_radius = old_radius } = new_style;
|
||||
// 选项卡背景设置
|
||||
const tabs_data = {
|
||||
color_list: tabs_bg_color_list,
|
||||
direction: tabs_bg_direction,
|
||||
background_img_style: tabs_bg_background_img_style,
|
||||
background_img: tabs_bg_background_img,
|
||||
};
|
||||
// 商品区域背景设置
|
||||
const data_content_data = {
|
||||
color_list: data_content_color_list,
|
||||
direction: data_content_direction,
|
||||
background_img_style: data_content_background_img_style,
|
||||
background_img: data_content_background_img,
|
||||
};
|
||||
const data_content = new_style?.data_content || old_border_and_box_shadow;
|
||||
const tabs_content = new_style?.tabs_content || old_border_and_box_shadow;
|
||||
|
||||
//显示的数据处理
|
||||
this.tabs_click_event(0);
|
||||
this.setData({
|
||||
top_up: new_content.tabs_top_up,
|
||||
sticky_top: this.propTop + (new_style?.tabs_margin?.margin_top || 0),
|
||||
data_tabs: new_data,
|
||||
// 自定义需要做等比缩放,因此宽度需要减去 外层通用的宽度和内容区域的宽度
|
||||
outer_container_width: common_style.margin_left + common_style.margin_right + common_style.padding_left + common_style.padding_right + new_style.data_content_margin.margin_left + new_style.data_content_margin.margin_right + new_style.data_content_padding.padding_left + new_style.data_content_padding.padding_right,
|
||||
style_container: common_styles_computer(common_style),
|
||||
style_img_container: common_img_computer(common_style, this.propIndex),
|
||||
tabs_style: new_tabs_style,
|
||||
tabs_sliding_fixed_bg: gradient_computer(tabs_data),
|
||||
tabs_container: gradient_computer(tabs_data) + radius_computer(tabs_radius) + margin_computer(new_style?.tabs_margin || old_margin) + border_computer(tabs_content) + box_shadow_computer(tabs_content) + 'overflow: hidden;',
|
||||
tabs_img_container: background_computer(tabs_data) + padding_computer(tabs_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
data_margin_top: 'margin-top:' + (new_style?.data_content_spacing || 0) * 2 + 'rpx;',
|
||||
data_container: gradient_computer(data_content_data) + margin_computer(data_content_margin) + radius_computer(data_content_radius) + box_shadow_computer(data_content) + border_computer(data_content) + 'overflow: hidden;',
|
||||
data_img_container: background_computer(data_content_data) + padding_computer(data_content_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
});
|
||||
},
|
||||
tabs_click_event(index) {
|
||||
let new_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
// 显示的数据处理
|
||||
const tabs_data_list = new_data.content.tabs_list[index] || {};
|
||||
const tabs_data_type = tabs_data_list?.tabs_data_type || '';
|
||||
let tabs_list = {};
|
||||
// 内容样式
|
||||
let data_content_container = '';
|
||||
let data_content_img_container = '';
|
||||
if (tabs_data_type === 'goods') {
|
||||
tabs_list = tabs_data_list.goods_config;
|
||||
const new_style = tabs_data_list.goods_config.style;
|
||||
// 内容样式
|
||||
data_content_container = common_styles_computer(new_style?.data_content_style || this.data_content_style);
|
||||
data_content_img_container = common_img_computer(new_style?.data_content_style || this.data_content_style);
|
||||
} else if (tabs_data_type === 'article') {
|
||||
tabs_list = tabs_data_list.article_config;
|
||||
const new_style = tabs_data_list.article_config.style;
|
||||
// 内容样式
|
||||
data_content_container = common_styles_computer(new_style?.data_content_style || this.data_content_style);
|
||||
data_content_img_container = common_img_computer(new_style?.data_content_style || this.data_content_style);
|
||||
} else if (tabs_data_type === 'custom') {
|
||||
tabs_list = tabs_data_list.custom_config;
|
||||
}
|
||||
this.setData({
|
||||
tabs_data_type: tabs_data_type,
|
||||
tabs_index: index,
|
||||
tabs_list: tabs_list,
|
||||
data_content_container: data_content_container,
|
||||
data_content_img_container: data_content_img_container,
|
||||
diy_key: get_math(),
|
||||
});
|
||||
},
|
||||
// 获取商品距离顶部的距离
|
||||
getTop() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.data-tabs-' + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_style = new_data.style || {};
|
||||
this.setData({
|
||||
tabs_top: res.top - (new_style.common_style?.margin_top || 0),
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
goods_buy_event(index, goods = {}, params = {}, back_data = null) {
|
||||
this.$emit('goods_buy_event', index, goods, params, back_data);
|
||||
},
|
||||
goods_cart_back_event(e) {
|
||||
if ((this.$refs.diy_goods_list || null) != null) {
|
||||
this.$refs.diy_goods_list.goods_cart_back_event(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
784
components/diy/diy.vue
Normal file
784
components/diy/diy.vue
Normal file
@@ -0,0 +1,784 @@
|
||||
<template>
|
||||
<view :style="page_style">
|
||||
<view :style="page_img_style">
|
||||
<scroll-view :scroll-y="true" class="ht" @scroll="on_scroll_event" @scrolltolower="on_scroll_lower_event" @scrolltoupper="on_scroll_upper_event" lower-threshold="60" scroll-with-animation="true">
|
||||
<!-- 头部小程序兼容 -->
|
||||
<view class="pr header">
|
||||
<componentDiyHeader :propKey="header_data.id" :propValue="header_data.com_data" :propScrollTop="head_scroll_top" @onImmersionModelCallBack="immersion_model_call_back" @onLocationBack="choice_location_back"></componentDiyHeader>
|
||||
</view>
|
||||
<view :style="content_padding">
|
||||
<view class="content flex-col" :style="'padding-top:calc(' + (temp_is_header_top ? temp_header_top + temp_sticky_top + 'px)' : '0px)')">
|
||||
<view v-for="item in tabs_data" :key="item.key">
|
||||
<template v-if="item.is_enable == '1'">
|
||||
<componentDiyTabs v-if="item.key == 'tabs'" :propIndex="is_immersive_style_and_general_safe_distance_value ? item.index : -1" :propContentPadding="content_padding" :propValue="item.com_data" :propTop="get_tabs_data_prop_top" :propStickyTop="get_tabs_data_prop_sticky_top" :propIsImmersionModel="is_immersion_model && is_the_safe_distance_enabled && item.com_data.content.tabs_top_up == '1'" :propNavIsTop="is_header_top" :propTabsIsTop="true" @onComputerHeight="tabs_height_event" @onTabsTap="tabs_click_event"></componentDiyTabs>
|
||||
<componentDiyTabsCarousel v-else-if="item.key == 'tabs-carousel'" :propIndex="is_immersive_style_and_general_safe_distance_value ? item.index : -1" :propContentPadding="content_padding" :propValue="item.com_data" :propTop="get_tabs_data_prop_top" :propStickyTop="get_tabs_data_prop_sticky_top" :propIsImmersionModel="is_immersion_model && is_the_safe_distance_enabled" :propScrollTop="scroll_top" :propTabsIsTop="true" @onComputerHeight="tabs_height_event" @onTabsTap="tabs_click_event" @onVideoPlay="video_play"></componentDiyTabsCarousel>
|
||||
</template>
|
||||
</view>
|
||||
<template v-if="is_tabs_type">
|
||||
<template v-if="diy_data.length > 0">
|
||||
<view v-for="(item, index) in diy_data" :key="index" :style="'margin-top:' + (['float-window'].includes(item.key) ? '0rpx;z-index:1' : -(item.com_data.style.common_style.floating_up * 2 || 0) + 'rpx;z-index:' + (!isEmpty(item.com_data.style.common_style.module_z_index) ? item.com_data.style.common_style.module_z_index : 0))">
|
||||
<!-- 基础组件 -->
|
||||
<template v-if="item.is_enable == '1'">
|
||||
<componentDiySearch v-if="item.key == 'search'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiySearch>
|
||||
<componentDiyCarousel v-else-if="item.key == 'carousel'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data" @onVideoPlay="video_play"></componentDiyCarousel>
|
||||
<componentDiyNavGroup v-else-if="item.key == 'nav-group'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyNavGroup>
|
||||
<componentDiyUserInfo v-else-if="item.key == 'user-info'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyUserInfo>
|
||||
<componentDiyNotice v-else-if="item.key == 'notice'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyNotice>
|
||||
<componentDiyVideo v-else-if="item.key == 'video'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyVideo>
|
||||
<componentDiyArticleList v-else-if="item.key == 'article-list'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyArticleList>
|
||||
<componentDiyArticleTabs v-else-if="item.key == 'article-tabs'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data" :propTop="get_diy_prop_top(item.com_data)" :propScrollTop="scroll_top" :propCustomNavHeight="get_diy_custom_nav_height(item.com_data)" :propIsTabsUseSafeDistance="getPropIsTabsUseSafeDistance"></componentDiyArticleTabs>
|
||||
<componentDataTabs v-else-if="item.key == 'data-tabs'" :ref="'diy_goods_buy' + index" :propIndex="get_prop_index(item)" :propDiyIndex="index" :propKey="item.id + index" :propValue="item.com_data" :propTop="get_diy_prop_top(item.com_data)" :propScrollTop="scroll_top" :propCustomNavHeight="get_diy_custom_nav_height(item.com_data)" :propIsTabsUseSafeDistance="getPropIsTabsUseSafeDistance" @goods_buy_event="goods_buy_event"></componentDataTabs>
|
||||
<componentDiyGoodsTabs v-else-if="item.key == 'goods-tabs'" :ref="'diy_goods_buy' + index" :propIndex="get_prop_index(item)" :propDiyIndex="index" :propKey="item.id + index" :propValue="item.com_data" :propTop="get_diy_prop_top(item.com_data)" :propScrollTop="scroll_top" :propCustomNavHeight="get_diy_custom_nav_height(item.com_data)" :propIsTabsUseSafeDistance="getPropIsTabsUseSafeDistance" @goods_buy_event="goods_buy_event"></componentDiyGoodsTabs>
|
||||
<componentDiyGoodsList v-else-if="item.key == 'goods-list'" :ref="'diy_goods_buy' + index" :propIndex="get_prop_index(item)" :propDiyIndex="index" :propKey="item.id + index" :propValue="item.com_data" @goods_buy_event="goods_buy_event"></componentDiyGoodsList>
|
||||
<componentDiyDataMagic v-else-if="item.key == 'data-magic'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyDataMagic>
|
||||
<componentDiyCustom v-else-if="item.key == 'custom'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyCustom>
|
||||
<componentDiyImgMagic v-else-if="item.key == 'img-magic'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyImgMagic>
|
||||
<componentDiyHotZone v-else-if="item.key == 'hot-zone'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyHotZone>
|
||||
<componentDiySeckill v-else-if="item.key == 'seckill'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiySeckill>
|
||||
<!-- 插件 -->
|
||||
<componentDiyCoupon v-else-if="item.key == 'coupon'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyCoupon>
|
||||
<!-- 工具组件 -->
|
||||
<componentDiyFloatWindow v-else-if="item.key == 'float-window'" :propKey="item.id + index" :propValue="item.com_data"></componentDiyFloatWindow>
|
||||
<componentDiyTitle v-else-if="item.key == 'title'" :propKey="item.id + index" :propIndex="get_prop_index(item)" :propValue="item.com_data"></componentDiyTitle>
|
||||
<componentDiyAuxiliaryLine v-else-if="item.key == 'row-line'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyAuxiliaryLine>
|
||||
<componentDiyRichText v-else-if="item.key == 'rich-text'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyRichText>
|
||||
<componentDiyAuxiliaryBlank v-else-if="item.key == 'auxiliary-blank'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyAuxiliaryBlank>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- diy底部卡槽 -->
|
||||
<slot name="diy-bottom-content"></slot>
|
||||
<slot name="diy-bottom-common"></slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 商品九宫格列表 -->
|
||||
<view v-if="goods_list.length > 0" class="padding-horizontal-main padding-top-main oh">
|
||||
<component-goods-list :propData="{ style_type: goods_show_type_value, goods_list: goods_list, random: random_value }" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol"></component-goods-list>
|
||||
</view>
|
||||
<view v-else class="pr">
|
||||
<!-- 提示信息 -->
|
||||
<component-no-data :propStatus="goods_list_loding_status" :propMsg="goods_list_loding_msg" propLoadingLogoTop="30%"></component-no-data>
|
||||
</view>
|
||||
|
||||
<!-- diy底部卡槽 -->
|
||||
<template v-if="goods_bottom_line_status">
|
||||
<slot name="diy-bottom-content"></slot>
|
||||
</template>
|
||||
<slot name="diy-bottom-common"></slot>
|
||||
</template>
|
||||
|
||||
<view class="z-i-deep">
|
||||
<!-- 商品购买 -->
|
||||
<component-goods-buy ref="goods_buy" v-on:CartSuccessEvent="goods_cart_back_event"></component-goods-buy>
|
||||
<!-- 视频播放 -->
|
||||
<uni-popup ref="popup" type="center" border-radius="20rpx" :mask-click="false">
|
||||
<view class="flex-col align-c jc-c gap-10">
|
||||
<video :src="video_src" id="carousel_video" :autoplay="true" :controls="true" show-fullscreen-btn class="radius-md" :style="{ width: popup_width, height: popup_height }"></video>
|
||||
<iconfont name="icon-qiandao-tancguanbi" size="56rpx" color="#ccc" propContainerDisplay="flex" @tap="video_close"></iconfont>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 当前diy页面底部菜单(非公共底部菜单) -->
|
||||
<block v-if="is_show_footer">
|
||||
<componentDiyFooter :propKey="footer_data.id" :propValue="footer_data.com_data" @onFooterHeight="footer_height_value_event"></componentDiyFooter>
|
||||
<view v-if="footer_height_value > 0" :style="'height:' + footer_height_value + 'rpx;'"></view>
|
||||
</block>
|
||||
|
||||
<!-- 底部卡槽 -->
|
||||
<slot name="bottom"></slot>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty, common_styles_computer, background_computer, padding_computer } from '@/common/js/common/common.js';
|
||||
import componentDiyHeader from '@/components/diy/header';
|
||||
import componentDiyFooter from '@/components/diy/footer';
|
||||
import componentDiyTabs from '@/components/diy/tabs';
|
||||
import componentDiySearch from '@/components/diy/search';
|
||||
import componentDiyCarousel from '@/components/diy/carousel';
|
||||
import componentDiyUserInfo from '@/components/diy/user-info';
|
||||
import componentDiyNotice from '@/components/diy/notice';
|
||||
import componentDiyVideo from '@/components/diy/video';
|
||||
import componentDiyArticleList from '@/components/diy/article-list';
|
||||
import componentDiyArticleTabs from '@/components/diy/article-tabs';
|
||||
import componentDiyHotZone from '@/components/diy/hot-zone';
|
||||
import componentDiyCoupon from '@/components/diy/coupon';
|
||||
import componentDiyFloatWindow from '@/components/diy/float-window';
|
||||
import componentDiyTitle from '@/components/diy/title';
|
||||
import componentDiyAuxiliaryLine from '@/components/diy/auxiliary-line';
|
||||
import componentDiyRichText from '@/components/diy/rich-text';
|
||||
import componentDiyAuxiliaryBlank from '@/components/diy/auxiliary-blank';
|
||||
import componentDiyNavGroup from '@/components/diy/nav-group';
|
||||
import componentDiyGoodsList from '@/components/diy/goods-list';
|
||||
import componentDiyGoodsTabs from '@/components/diy/goods-tabs';
|
||||
import componentDiyDataMagic from '@/components/diy/data-magic';
|
||||
import componentDiyCustom from '@/components/diy/custom';
|
||||
import componentDiyImgMagic from '@/components/diy/img-magic';
|
||||
import componentDiySeckill from '@/components/diy/seckill';
|
||||
import componentDiyTabsCarousel from '@/components/diy/tabs-carousel';
|
||||
import componentDataTabs from '@/components/diy/data-tabs';
|
||||
import componentGoodsList from '@/components/goods-list/goods-list';
|
||||
import componentNoData from '@/components/no-data/no-data';
|
||||
import componentBottomLine from '@/components/bottom-line/bottom-line';
|
||||
import componentGoodsBuy from '@/components/goods-buy/goods-buy';
|
||||
import componentSearch from '@/components/search/search';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
name: 'diy',
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propDataId: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
componentDiyHeader,
|
||||
componentDiyFooter,
|
||||
componentDiyTabs,
|
||||
componentDiySearch,
|
||||
componentDiyCarousel,
|
||||
componentDiyUserInfo,
|
||||
componentDiyNotice,
|
||||
componentDiyVideo,
|
||||
componentDiyArticleList,
|
||||
componentDiyArticleTabs,
|
||||
componentDiyHotZone,
|
||||
componentDiyCoupon,
|
||||
componentDiyAuxiliaryLine,
|
||||
componentDiyRichText,
|
||||
componentDiyFloatWindow,
|
||||
componentDiyTitle,
|
||||
componentDiyAuxiliaryBlank,
|
||||
componentDiyNavGroup,
|
||||
componentDiyGoodsList,
|
||||
componentDiyGoodsTabs,
|
||||
componentDiyDataMagic,
|
||||
componentDiyCustom,
|
||||
componentDiyImgMagic,
|
||||
componentDiySeckill,
|
||||
componentDiyTabsCarousel,
|
||||
componentDataTabs,
|
||||
componentGoodsList,
|
||||
componentNoData,
|
||||
componentBottomLine,
|
||||
componentGoodsBuy,
|
||||
componentSearch,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 基础配置
|
||||
currency_symbol: app.globalData.currency_symbol(),
|
||||
// 是否有选项卡
|
||||
is_tabs: false,
|
||||
// 是否是模块数据或者是九宫格商品分类样式数据, 默认模块数据
|
||||
is_tabs_type: true,
|
||||
// 是否开启沉浸模式
|
||||
is_immersion_model: false,
|
||||
|
||||
// 5,7,0 是误差,, 10 是下边距,66是高度,bar_height是不同小程序下的导航栏距离顶部的高度
|
||||
// #ifdef MP
|
||||
sticky_top: bar_height + 5 + 10,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
sticky_top: bar_height + 7 + 10,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
sticky_top: bar_height + 0 + 10,
|
||||
// #endif
|
||||
header_top: '',
|
||||
temp_sticky_top: 0,
|
||||
temp_header_top: '0px',
|
||||
is_header_top: false,
|
||||
temp_is_header_top: false,
|
||||
scroll_top: 0,
|
||||
// 选项卡高度
|
||||
tabs_height: 0,
|
||||
|
||||
header_data: {},
|
||||
footer_data: {},
|
||||
// 选项卡数据
|
||||
tabs_data: {},
|
||||
diy_data: [],
|
||||
page_style: '',
|
||||
page_img_style: '',
|
||||
is_show_footer: false,
|
||||
tabs_home_id: this.propDataId,
|
||||
// 商品列表
|
||||
goods_list: [],
|
||||
goods_total: 0,
|
||||
goods_page_total: 0,
|
||||
goods_page: 1,
|
||||
// 数据展示样式(0图文、1九方格)
|
||||
goods_show_type_value: 1,
|
||||
// 增加随机数,避免无法监听数据列表内部数据更新
|
||||
random_value: 0,
|
||||
// 标签插件
|
||||
plugins_label_data: null,
|
||||
goods_list_loding_status: 1,
|
||||
goods_list_loding_msg: '',
|
||||
goods_bottom_line_status: false,
|
||||
// 判断数据是否在加载中
|
||||
data_is_loading: 0,
|
||||
// 缓存key
|
||||
cache_key: app.globalData.data.cache_diy_data_key,
|
||||
// 底部导航高度
|
||||
footer_height_value: 0,
|
||||
// 商品ref索引
|
||||
goods_index: 0,
|
||||
// 视频播放逻辑
|
||||
video_src: '',
|
||||
popup_width: '0rpx',
|
||||
popup_height: '0rpx',
|
||||
// 顶部导航是否换行
|
||||
is_search_alone_row: false,
|
||||
data_alone_row_space: 0,
|
||||
content_padding: '',
|
||||
outer_container_padding: 0,
|
||||
|
||||
// 滚动延迟器
|
||||
head_scroll_top: 0,
|
||||
scroll_throttle_timeout: null,
|
||||
// 是否开启安全距离
|
||||
is_the_safe_distance_enabled: false,
|
||||
// 是否开启置顶
|
||||
is_tabs_data_topped: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
get_tabs_data_prop_top() {
|
||||
// 开启了沉浸式时的处理
|
||||
if (this.is_immersion_model) {
|
||||
// 并且开启了安全距离
|
||||
return this.is_the_safe_distance_enabled ? this.temp_header_top : 0;
|
||||
} else {
|
||||
return this.temp_header_top;
|
||||
}
|
||||
},
|
||||
get_tabs_data_prop_sticky_top() {
|
||||
// 开启了沉浸式时的处理
|
||||
if (this.is_immersion_model) {
|
||||
// 并且开启了安全距离
|
||||
return this.is_the_safe_distance_enabled ? this.temp_sticky_top : 0;
|
||||
} else {
|
||||
return this.temp_sticky_top;
|
||||
}
|
||||
},
|
||||
get_prop_index() {
|
||||
return (item) => {
|
||||
return this.is_the_safe_distance_enabled && this.tabs_data.length == 0 ? item.index : -1;
|
||||
}
|
||||
},
|
||||
get_diy_prop_top() {
|
||||
return (item) => {
|
||||
// 不开启沉浸模式时的处理
|
||||
if (!this.is_immersion_model) {
|
||||
return this.temp_sticky_top + this.tabs_height;
|
||||
} else {
|
||||
// 开启沉浸模式且开启选项卡置顶时
|
||||
if (this.is_tabs_data_topped) {
|
||||
return this.tabs_height;
|
||||
} else {
|
||||
// 开启安全距离
|
||||
let is_general_safe_distance_num = this.temp_sticky_top;
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
is_general_safe_distance_num = this.is_header_top ? this.temp_sticky_top : 0
|
||||
// #endif
|
||||
if (this.is_the_safe_distance_enabled) {
|
||||
return is_general_safe_distance_num;
|
||||
} else {
|
||||
if (item?.content?.is_general_safe_distance == '1') {
|
||||
return is_general_safe_distance_num;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
get_diy_custom_nav_height() {
|
||||
return (item) => {
|
||||
let header_height = (this.is_search_alone_row ? 66 + this.data_alone_row_space : 33);
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
header_height = this.is_header_top ? header_height : 0;
|
||||
// #endif
|
||||
// 不开启沉浸模式时的处理
|
||||
if (!this.is_immersion_model) {
|
||||
return header_height;
|
||||
} else {
|
||||
// 开启沉浸模式且开启选项卡置顶时
|
||||
if (this.is_tabs_data_topped) {
|
||||
return 0;
|
||||
} else {
|
||||
// 开启沉浸模式时并且开启安全距离
|
||||
if (this.is_the_safe_distance_enabled) {
|
||||
return this.is_search_alone_row ? 66 + this.data_alone_row_space : 33;
|
||||
} else {
|
||||
if (item?.content?.is_general_safe_distance == '1') {
|
||||
return header_height;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getPropIsTabsUseSafeDistance() {
|
||||
let is_tabs_use_safe_distance = this.is_immersion_model;
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
is_tabs_use_safe_distance = this.is_immersion_model && this.is_header_top;
|
||||
// #endif
|
||||
return is_tabs_use_safe_distance || !this.is_immersion_model;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 如果当前存在别的diy或者商品分类tabs则不更新数据
|
||||
if ((this.tabs_id || null) == null) {
|
||||
// 初始化
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 初始化配置
|
||||
this.init_config();
|
||||
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
// 初始化配置
|
||||
init_config(status) {
|
||||
if ((status || false) == true) {
|
||||
// 是否显示底部菜单,如果当前地址已经存在系统底部菜单中则不显示当前diy页面自定义的底部菜单
|
||||
var is_show_footer = parseInt(this.propValue.header.com_data.content.bottom_navigation_show || 0) == 1;
|
||||
var is_tabbar = app.globalData.is_tabbar_pages();
|
||||
this.setData({
|
||||
is_show_footer: is_show_footer && !is_tabbar,
|
||||
});
|
||||
// diy页面不显示底部菜单则设置底部菜单高度为0
|
||||
if(!this.is_show_footer) {
|
||||
// 存储diy页面底部菜单高度
|
||||
if(app.globalData.current_page(false) == 'pages/diy/diy') {
|
||||
app.globalData.app_diy_tabbar_height_save(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app.globalData.is_config(this, 'init_config');
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化
|
||||
init() {
|
||||
const { header = {}, diy_data = [], tabs_data = [] } = this.propValue;
|
||||
// 头部的样式
|
||||
let header_style = header.com_data.style;
|
||||
let new_diy_index = 0;
|
||||
let new_tabs_data = [];
|
||||
let new_diy_data = [];
|
||||
if (tabs_data.length > 0) {
|
||||
tabs_data.forEach((item) => {
|
||||
// 修改item的内容
|
||||
item = this.get_index_content(new_diy_index, header, header_style, item);
|
||||
new_tabs_data.push(item);
|
||||
new_diy_index++;
|
||||
});
|
||||
new_diy_data = diy_data;
|
||||
} else {
|
||||
new_tabs_data = tabs_data;
|
||||
// 过滤数据
|
||||
diy_data.forEach((item) => {
|
||||
// 判断是否是商品列表
|
||||
if (item.com_name == 'float-window') {
|
||||
item.index = -1;
|
||||
} else {
|
||||
// 修改item的内容
|
||||
item = this.get_index_content(new_diy_index, header, header_style, item);
|
||||
new_diy_data.push(item);
|
||||
new_diy_index++;
|
||||
}
|
||||
});
|
||||
}
|
||||
const { padding_right = 0, padding_left = 0 } = header_style.common_style;
|
||||
const new_is_search_alone_row = header.com_data.content.data_alone_row_value.length > 0 ? true : false;
|
||||
const new_data_alone_row_space = parseInt(header_style.data_alone_row_space || 0);
|
||||
// tabs选项卡数据过滤
|
||||
this.setData({
|
||||
header_data: header,
|
||||
footer_data: this.propValue.footer,
|
||||
diy_data: new_diy_data,
|
||||
tabs_data: new_tabs_data,
|
||||
page_style: common_styles_computer(header_style.common_style),
|
||||
page_img_style: background_computer(header_style.common_style),
|
||||
// 内间距
|
||||
content_padding: `padding: 0px ${padding_right}px 0px ${padding_left}px;` + 'box-sizing:border-box;',
|
||||
outer_container_padding: padding_right + padding_left,
|
||||
// 判断顶部导航是否置顶
|
||||
is_header_top: parseInt(header_style.up_slide_display) == 1 ? true : false,
|
||||
is_tabs_data_topped: new_tabs_data[0]?.com_data?.content?.tabs_top_up == '1' || false,
|
||||
temp_sticky_top: this.sticky_top,
|
||||
temp_header_top: (new_is_search_alone_row ? 66 + new_data_alone_row_space : 33),
|
||||
header_top: (new_is_search_alone_row ? 66 + new_data_alone_row_space : 33),
|
||||
is_immersion_model: header_style.header_background_type !== 'color_image' && header_style.immersive_style == '1',
|
||||
// 顶部导航高度是否变化--------------------------------------------------
|
||||
is_search_alone_row: new_is_search_alone_row,
|
||||
data_alone_row_space: new_data_alone_row_space,
|
||||
is_immersive_style_and_general_safe_distance_value: header_style.immersive_style == '1' && header_style.general_safe_distance_value == '1',
|
||||
is_the_safe_distance_enabled: header_style.immersive_style == '1' && header_style.general_safe_distance_value == '1',// diy_data是否开启安全距离
|
||||
});
|
||||
// 缓存数据
|
||||
uni.setStorageSync(this.cache_key + this.tabs_home_id, diy_data);
|
||||
},
|
||||
// 顶部导航沉浸模式回调
|
||||
// immersion_model_call_back(bool) {
|
||||
// this.setData({
|
||||
// is_immersion_model: bool,
|
||||
// });
|
||||
// },
|
||||
get_index_content(new_diy_index, header, header_style, item) {
|
||||
item.index = new_diy_index;
|
||||
if (new_diy_index == 0) {
|
||||
// 判断是否开启沉浸模式和是否开启安全距离 如果为true则除了选项卡和选项卡轮播外, 第一个组件则加上安全距离样式的padding_top加上顶部导航的高度和安全距离的高度
|
||||
if (header_style.immersive_style == '1' && header_style.general_safe_distance_value == '1') {
|
||||
let new_data = JSON.parse(JSON.stringify(item));
|
||||
// 顶部导航的高度
|
||||
let header_top_height = (header.com_data.content.data_alone_row_value.length > 0 ? parseInt(header.com_data.style.data_alone_row_space || 5) : 0) + 33 + (header.com_data.content.data_alone_row_value.length > 0 ? 33 : 0);
|
||||
new_data.com_data.style.common_style.padding_top = parseInt(new_data.com_data.style.common_style.padding_top) + header_top_height;
|
||||
return new_data;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
return item;
|
||||
},
|
||||
// 选项卡回调更新数据
|
||||
tabs_click_event(tabs_id, bool, params = {}) {
|
||||
let new_data = [];
|
||||
this.setData({
|
||||
is_tabs_type: bool,
|
||||
tabs_id: tabs_id,
|
||||
});
|
||||
let new_params = {
|
||||
...params,
|
||||
id: tabs_id,
|
||||
};
|
||||
if (tabs_id) {
|
||||
new_data = uni.getStorageSync(this.cache_key + tabs_id) || [];
|
||||
if (new_data.length > 0) {
|
||||
// 先使用缓存数据展示
|
||||
this.setData({
|
||||
diy_data: new_data,
|
||||
});
|
||||
// 已有本地缓存则直接取远程有效数据(默认首次取的是远程缓存数据)
|
||||
new_params['is_cache'] = 0;
|
||||
}
|
||||
// diy数据
|
||||
if (bool) {
|
||||
uni.showLoading({
|
||||
title: this.$t('common.loading_in_text'),
|
||||
mask: true,
|
||||
});
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('index', 'diy'),
|
||||
method: 'POST',
|
||||
data: new_params,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
uni.hideLoading();
|
||||
// 数据处理
|
||||
let data = res.data.data.data;
|
||||
if (res.data.code == 0) {
|
||||
new_data = data?.config.diy_data || [];
|
||||
uni.setStorageSync(this.cache_key + tabs_id, new_data);
|
||||
this.setData({
|
||||
diy_data: new_data,
|
||||
});
|
||||
// 是否需要重新加载数据
|
||||
if (parseInt(data.is_result_data_cache || 0) == 1) {
|
||||
this.tabs_click_event(tabs_id, bool, { is_cache: 0 });
|
||||
}
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
goods_page: 1,
|
||||
goods_list: [],
|
||||
goods_list_loding_status: 1,
|
||||
goods_bottom_line_status: false,
|
||||
});
|
||||
this.get_goods_list(1);
|
||||
}
|
||||
} else {
|
||||
if (tabs_id == '') {
|
||||
new_data = uni.getStorageSync(this.cache_key + this.tabs_home_id) || [];
|
||||
}
|
||||
// 先使用缓存数据展示
|
||||
this.setData({
|
||||
diy_data: new_data,
|
||||
});
|
||||
}
|
||||
},
|
||||
// 选项卡高度
|
||||
tabs_height_event(height) {
|
||||
let new_tabs_height = 0;
|
||||
// 判断是否有选项卡切选项卡数组数据内的字段is_enable值是否为1
|
||||
if (this.tabs_data.length > 0) {
|
||||
this.tabs_data.forEach((item, index) => {
|
||||
if (item.is_enable == '1') {
|
||||
new_tabs_height = height;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.setData({
|
||||
tabs_height: new_tabs_height,
|
||||
});
|
||||
},
|
||||
|
||||
// 滚动加载
|
||||
on_scroll_lower_event(e) {
|
||||
if (!this.is_tabs_type) {
|
||||
this.get_goods_list();
|
||||
}
|
||||
},
|
||||
// 滚动到顶部
|
||||
on_scroll_upper_event() {
|
||||
setTimeout(() => {
|
||||
this.head_scroll_top = 0;
|
||||
});
|
||||
},
|
||||
|
||||
// 查询商品
|
||||
get_goods_list(is_mandatory) {
|
||||
// 分页是否还有数据
|
||||
if ((is_mandatory || 0) == 0) {
|
||||
if (this.goods_bottom_line_status == true) {
|
||||
uni.stopPullDownRefresh();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 是否加载中
|
||||
if (this.data_is_loading == 1) {
|
||||
return false;
|
||||
}
|
||||
this.setData({
|
||||
data_is_loading: 1,
|
||||
});
|
||||
|
||||
// 获取数据
|
||||
if (this.goods_page > 1) {
|
||||
uni.showLoading({
|
||||
title: this.$t('common.loading_in_text'),
|
||||
});
|
||||
}
|
||||
let new_data = {
|
||||
category_id: this.tabs_id,
|
||||
page: this.goods_page,
|
||||
};
|
||||
// 九宫格数据
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('datalist', 'search'),
|
||||
method: 'POST',
|
||||
data: new_data,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if (this.goods_page > 1) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
uni.stopPullDownRefresh();
|
||||
if (res.data.code == 0) {
|
||||
var data = res.data.data;
|
||||
if (data.data.length > 0) {
|
||||
if (this.goods_page <= 1) {
|
||||
var temp_goods_list = data.data;
|
||||
} else {
|
||||
var temp_goods_list = this.goods_list || [];
|
||||
var temp_data = data.data;
|
||||
for (var i in temp_data) {
|
||||
temp_goods_list.push(temp_data[i]);
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
goods_list: temp_goods_list,
|
||||
random_value: Math.random(),
|
||||
goods_total: data.total,
|
||||
goods_page_total: data.page_total,
|
||||
goods_list_loding_status: 3,
|
||||
goods_list_loding_msg: '',
|
||||
goods_page: this.goods_page + 1,
|
||||
data_is_loading: 0,
|
||||
});
|
||||
|
||||
// 是否还有数据
|
||||
this.setData({
|
||||
goods_bottom_line_status: this.goods_page > 1 && this.goods_page > this.goods_page_total,
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
goods_list_loding_status: 0,
|
||||
goods_list_loding_msg: res.data.msg,
|
||||
goods_total: 0,
|
||||
data_is_loading: 0,
|
||||
});
|
||||
if (this.goods_page <= 1) {
|
||||
this.setData({
|
||||
goods_list: [],
|
||||
goods_bottom_line_status: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.setData({
|
||||
goods_list_loding_status: 0,
|
||||
goods_list_loding_msg: res.data.msg,
|
||||
data_is_loading: 0,
|
||||
});
|
||||
app.globalData.is_login_check(res.data, this, 'get_goods_list', is_mandatory);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
if (this.goods_page > 1) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
uni.stopPullDownRefresh();
|
||||
this.setData({
|
||||
goods_list_loding_status: 2,
|
||||
goods_list_loding_msg: this.$t('common.internet_error_tips'),
|
||||
data_is_loading: 0,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 页面滚动事件
|
||||
on_scroll_event(e) {
|
||||
const scroll_num = parseInt(e.detail.scrollTop);
|
||||
if (scroll_num <= 20) {
|
||||
this.head_scroll_top = 0;
|
||||
} else {
|
||||
if (scroll_num / (this.sticky_top + 33) <= 1) {
|
||||
// 更新数据的逻辑
|
||||
this.head_scroll_top = scroll_num;
|
||||
} else {
|
||||
this.head_scroll_top = this.sticky_top + 100;
|
||||
}
|
||||
}
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// 判断顶部导航是否置顶
|
||||
if (!this.is_header_top && !this.is_immersion_model) {
|
||||
if (scroll_num >= this.sticky_top + 33 + (this.is_search_alone_row ? 0 : 33 + this.data_alone_row_space)) {
|
||||
this.temp_sticky_top = 0;
|
||||
this.temp_header_top = 0;
|
||||
this.temp_sticky_no_h5_top = 0;
|
||||
this.temp_is_header_top = true;
|
||||
} else {
|
||||
this.temp_header_top = this.header_top;
|
||||
this.temp_sticky_top = this.sticky_top;
|
||||
this.temp_sticky_no_h5_top = this.sticky_top;
|
||||
this.temp_is_header_top = false;
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
this.scroll_timer_compute(scroll_num);
|
||||
},
|
||||
|
||||
scroll_timer_compute(scroll_num) {
|
||||
// 使用节流技术减少事件触发的处理次数
|
||||
if (!this.scroll_throttle_timeout) {
|
||||
const self = this;
|
||||
this.scroll_throttle_timeout = setTimeout(() => {
|
||||
this.scroll_top = scroll_num;
|
||||
// 清除定时器
|
||||
this.scroll_throttle_timeout = null;
|
||||
}, 20); // 可以根据实际情况调整延时时间
|
||||
}
|
||||
},
|
||||
|
||||
// 底部菜单高度
|
||||
footer_height_value_event(value) {
|
||||
this.setData({
|
||||
footer_height_value: (value*2)+20,
|
||||
});
|
||||
|
||||
// 存储diy页面底部菜单高度
|
||||
if(app.globalData.current_page(false) == 'pages/diy/diy') {
|
||||
app.globalData.app_diy_tabbar_height_save(value);
|
||||
}
|
||||
},
|
||||
// 商品数量更新回调
|
||||
goods_buy_event(index, goods = {}, params = {}, back_data = null) {
|
||||
if ((this.$refs.goods_buy || null) != null) {
|
||||
this.goods_index = index;
|
||||
this.$refs.goods_buy.init(goods, params, back_data);
|
||||
}
|
||||
},
|
||||
// 商品加购回调
|
||||
goods_cart_back_event(e) {
|
||||
if ((this.$refs[`diy_goods_buy${this.goods_index}`][0] || null) != null) {
|
||||
this.$refs[`diy_goods_buy${this.goods_index}`][0].goods_cart_back_event(e);
|
||||
}
|
||||
},
|
||||
// 视频播放
|
||||
video_play(url, width, height) {
|
||||
this.setData({
|
||||
video_src: url,
|
||||
popup_width: width,
|
||||
popup_height: height,
|
||||
});
|
||||
this.$refs.popup.open();
|
||||
const videoContext = uni.createVideoContext('carousel_video');
|
||||
if (!isEmpty(videoContext)) {
|
||||
videoContext.play();
|
||||
}
|
||||
},
|
||||
// 视频关闭
|
||||
video_close() {
|
||||
const videoContext = uni.createVideoContext('carousel_video');
|
||||
if (!isEmpty(videoContext)) {
|
||||
videoContext.pause();
|
||||
}
|
||||
this.$refs.popup.close();
|
||||
},
|
||||
// 位置回调
|
||||
choice_location_back(e) {
|
||||
// 如果存在tabs_id则表示当前有选择tab数据则仅当前模块更新,无需给上级回调位置
|
||||
if ((this.tabs_id || null) == null) {
|
||||
this.$emit('onLocationBack', e);
|
||||
} else {
|
||||
this.tabs_click_event(this.tabs_id, this.is_tabs_type);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
164
components/diy/float-window.vue
Normal file
164
components/diy/float-window.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<movable-area class="float-window-movable-container">
|
||||
<movable-view :x="x" :y="y" direction="all" class="float-window-spread flex-row align-c jc-c" @tap="btn_event">
|
||||
<block v-if="style.float_style == 'diffuse'">
|
||||
<view class="ring" :style="content_style"></view>
|
||||
<view class="ring" :style="content_style"></view>
|
||||
</block>
|
||||
<view class="img oh" :style="content_style">
|
||||
<block v-if="(form || null) != null && form.button_jump == 'customer_service'">
|
||||
<component-online-service :propChatImage="img_url" :propIsSpread="false" :propIsMovable="false"></component-online-service>
|
||||
</block>
|
||||
<block v-else>
|
||||
<imageEmpty :propImageSrc="img_url" propImgFit="aspectFill" propErrorStyle="width: 60rpx;height: 60rpx;"></imageEmpty>
|
||||
</block>
|
||||
</view>
|
||||
</movable-view>
|
||||
<component-quick-nav ref="quick_nav" :propIsBtn="false"></component-quick-nav>
|
||||
</movable-area>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import componentOnlineService from '@/components/online-service/online-service';
|
||||
import componentQuickNav from '@/components/quick-nav/quick-nav';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
componentOnlineService,
|
||||
componentQuickNav
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
style: {},
|
||||
img_url: '',
|
||||
x: 0,
|
||||
y: 0,
|
||||
content_style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
// 获取内容
|
||||
let form = this.propValue.content || {};
|
||||
// 获取图片
|
||||
let img_url = (form.button_img || null) != null ? (form.button_img[0] || null) : null;
|
||||
if (img_url != null) {
|
||||
img_url = img_url.url || null;
|
||||
}
|
||||
const { float_style, float_style_color, display_location, offset_number_percentage } = this.propValue.style;
|
||||
// 获取当前手机的宽度和高度
|
||||
const { windowWidth, windowHeight } = uni.getSystemInfoSync();
|
||||
// 计算出距离左边的距离
|
||||
let x = display_location == 'left' ? 10 : windowWidth - 60;
|
||||
// 计算出距离顶部的距离
|
||||
const y = Math.ceil(windowHeight * (1 - Number(offset_number_percentage)) - 20);
|
||||
this.setData({
|
||||
form: form,
|
||||
style: this.propValue.style,
|
||||
img_url: img_url,
|
||||
content_style: float_style == 'shadow' ? `box-shadow: 0 0 40rpx ${float_style_color};border-radius: 50%;` : `background-color: ${float_style_color};border-radius: 50%;`,
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
},
|
||||
// 按钮事件
|
||||
btn_event() {
|
||||
const { button_jump, button_link } = this.form;
|
||||
switch(button_jump) {
|
||||
// 链接
|
||||
case 'link' :
|
||||
if (!isEmpty(button_link)) {
|
||||
app.globalData.url_open(button_link.page);
|
||||
}
|
||||
break;
|
||||
// 快捷导航
|
||||
case 'quick_nav' :
|
||||
if ((this.$refs.quick_nav || null) != null) {
|
||||
this.$refs.quick_nav.quick_open_event();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.img {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
border-radius: 50%;
|
||||
z-index: 2;
|
||||
}
|
||||
.float-window-movable-container {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
z-index: 103;
|
||||
}
|
||||
/**
|
||||
* 呼吸灯
|
||||
*/
|
||||
.float-window-spread {
|
||||
position: relative;
|
||||
pointer-events: auto;
|
||||
z-index: 1;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.float-window-spread .ring {
|
||||
/* 速度为1.5 * 层数 = 实际运行速度,速度修改则 animation-delay 属性也修改相同速度 */
|
||||
animation: pulsing 1.5s ease-out infinite;
|
||||
border-radius: 100%;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
position: absolute;
|
||||
}
|
||||
/* 速度为1*层数 */
|
||||
.float-window-spread .ring:nth-of-type(1) {
|
||||
-webkit-animation-delay: -1.5s;
|
||||
animation-delay: -1.5s;
|
||||
}
|
||||
|
||||
/* 速度为1*层数 */
|
||||
.float-window-spread .ring:nth-of-type(2) {
|
||||
-webkit-animation-delay: -2s;
|
||||
animation-delay: -2s;
|
||||
}
|
||||
@keyframes pulsing {
|
||||
100% {
|
||||
transform: scale(1.35);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
201
components/diy/footer.vue
Normal file
201
components/diy/footer.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<!-- 底部导航 -->
|
||||
<view v-if="(propValue || null) !== null" class="footer-nav flex-row jc-c align-c" :class="nav_type == 1 ? 'bottom-line-exclude' : ''">
|
||||
<view class="flex-1 wh-auto" :style="style_container">
|
||||
<view class="footer-nav-content flex-row jc-c align-c wh-auto" :style="style_img_container">
|
||||
<view class="flex-row jc-c align-c wh-auto" :class="nav_type == 0 ? 'bottom-line-exclude' : ''">
|
||||
<view class="flex-row jc-sa align-c wh padding-0">
|
||||
<block v-for="(item, index) in nav_content" :key="index">
|
||||
<view class="flex-1 flex-col jc-c align-c gap-5 pr" :data-value="item.link.page || ''" @tap="url_event">
|
||||
<view v-if="nav_style != 2" class="img-content pr">
|
||||
<view class="img-item pa border-radius-xs animate-linear" :class="active_index != index ? 'active' : ''">
|
||||
<template v-if="item.img.length > 0">
|
||||
<image :src="item.img[0].url" class="img dis-block" model="widthFix"></image>
|
||||
</template>
|
||||
</view>
|
||||
<view class="img-item pa border-radius-xs animate-linear" :class="active_index == index ? 'active' : ''">
|
||||
<template v-if="item.img_checked.length > 0">
|
||||
<image :src="item.img_checked[0].url" class="img dis-block" model="widthFix"></image>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<text v-if="nav_style != 1" class="animate-linear text-size-xs pr z-i" :style="active_index == index ? text_color_checked : default_text_color">{{ item.name }}</text>
|
||||
<view v-if="(item.badge || null) != null" class="pa badge-icon">
|
||||
<component-badge :propNumber="item.badge"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
let app = getApp();
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
import componentBadge from '@/components/badge/badge';
|
||||
export default {
|
||||
props: {
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
// 底部选中索引
|
||||
propFooterActiveIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
nav_content: [],
|
||||
nav_type: 0,
|
||||
nav_style: 0,
|
||||
default_text_color: '',
|
||||
text_color_checked: '',
|
||||
active_index: 0,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
componentBadge,
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 唯一key
|
||||
propKey(value, old_value) {
|
||||
this.init();
|
||||
},
|
||||
// 选中索引
|
||||
propFooterActiveIndex(value, old_value) {
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化
|
||||
init() {
|
||||
if ((this.propValue || null) !== null) {
|
||||
let new_content = this.propValue.content || {};
|
||||
let new_style = this.propValue.style || {};
|
||||
let nav_content = new_content.nav_content || [];
|
||||
let page = app.globalData.current_page() || null;
|
||||
let active_index = this.propFooterActiveIndex;
|
||||
if (page != null) {
|
||||
// 角标链接定义
|
||||
let badge_arr = {
|
||||
'/pages/cart/cart': 'cart',
|
||||
'/pages/cart-page/cart-page': 'cart',
|
||||
};
|
||||
for (var i in nav_content) {
|
||||
if ((nav_content[i]['link'] || null) != null && (nav_content[i]['link']['page'] || null) != null) {
|
||||
// 选中索引
|
||||
if (nav_content[i]['link']['page'] == '/' + page) {
|
||||
active_index = i;
|
||||
}
|
||||
|
||||
// 获取角标数据
|
||||
var badge_key = badge_arr[nav_content[i]['link']['page']];
|
||||
if (badge_key !== undefined) {
|
||||
nav_content[i]['badge'] = app.globalData.get_tab_bar_badge(badge_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
nav_content: nav_content,
|
||||
nav_type: new_content.nav_type || 0,
|
||||
nav_style: new_content.nav_style || 0,
|
||||
active_index: active_index,
|
||||
default_text_color: 'color:' + new_style.default_text_color || 'rgba(0, 0, 0, 1)',
|
||||
text_color_checked: 'color:' + new_style.text_color_checked || 'rgba(204, 204, 204, 1)',
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style),
|
||||
});
|
||||
|
||||
// 高度计算
|
||||
let nav_min_height = 70;
|
||||
var nav_height = parseInt(new_style.common_style.padding_top) + parseInt(new_style.common_style.padding_bottom) + 44;
|
||||
if (nav_height < nav_min_height) {
|
||||
nav_height = nav_min_height;
|
||||
}
|
||||
let footer_height = nav_height + parseInt(new_style.common_style.margin_top) + parseInt(new_style.common_style.margin_bottom);
|
||||
|
||||
// #ifndef H5
|
||||
// 底部菜单距离底部的安全距离,减去20、默认的安全距离太高了
|
||||
var safe_areaInsets = uni.getSystemInfoSync().safeAreaInsets || {};
|
||||
var bottom = parseInt(safe_areaInsets.bottom || 0);
|
||||
if (bottom > 0) {
|
||||
bottom -= 24;
|
||||
}
|
||||
footer_height += bottom;
|
||||
// #endif
|
||||
|
||||
// 回调高度
|
||||
this.$emit('onFooterHeight', footer_height);
|
||||
}
|
||||
},
|
||||
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
let index = e.currentTarget.dataset.index;
|
||||
let item = this.nav_content[index];
|
||||
app.globalData.url_event(e);
|
||||
this.$emit('onFooterTap', index, item);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.footer-nav {
|
||||
z-index: 102;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
background-color: transparent;
|
||||
.footer-nav-content {
|
||||
min-height: 140rpx;
|
||||
box-sizing: border-box;
|
||||
.img-content {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
.img-item {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
opacity: 0;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
.img {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.badge-icon {
|
||||
margin-top: -70rpx;
|
||||
margin-right: -70rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* #ifdef H5 */
|
||||
@media only screen and (min-width: 1600rpx) {
|
||||
.footer-nav {
|
||||
max-width: 1600rpx;
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
607
components/diy/goods-list.vue
Normal file
607
components/diy/goods-list.vue
Normal file
@@ -0,0 +1,607 @@
|
||||
<template>
|
||||
<view v-if="!isEmpty(list)" class="oh" :style="style_container" @tap.stop="onTap">
|
||||
<view class="oh" :style="style_img_container">
|
||||
<view :class="outer_class" :style="onter_style">
|
||||
<block v-if="!['5'].includes(theme)">
|
||||
<view v-for="(item, index) in list" :key="index" class="pr oh" :style="layout_style" :data-index="index" :data-value="item.goods_url" @tap.stop="url_event">
|
||||
<view :class="layout_type" :style="layout_img_style">
|
||||
<block v-if="theme == '6'">
|
||||
<view :class="['flex-row align-c jc-sb ptb-15 mlr-10 gap-20', { 'br-b-e': index != list.length - 1 }]">
|
||||
<view v-if="is_show('title')" :class="text_line" :style="title_style">{{ item.title }}</view>
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num nowrap" :style="'color:' + new_style.shop_price_color">
|
||||
<text class="identifying">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" class="identifying">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<block v-if="!isEmpty(item)">
|
||||
<view class="oh pr" :class="img_size">
|
||||
<view v-if="!isEmpty(item.new_cover)" :style="img_size">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="content_img_radius" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-else :style="img_size">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="content_img_radius" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</block>
|
||||
<view v-if="is_show('title') || is_show('simple_desc') || is_show('price') || is_show('original_price') || is_show('sales_count') || is_show('plugins_view_icon') || form.is_shop_show == '1'" class="flex-col flex-1 jc-sb content gap-10" :style="content_style">
|
||||
<view class="flex-col gap-10 top-title">
|
||||
<view v-if="is_show('title') || (['0', '1', '2', '3', '5'].includes(theme) && is_show('simple_desc'))" class="flex-col" :style="{ gap: new_style.title_simple_desc_spacing * 2 + 'rpx' }">
|
||||
<view v-if="is_show('title')" :class="text_line" :style="title_style">{{ item.title }}</view>
|
||||
<view v-if="['0', '1', '2', '3', '5'].includes(theme) && is_show('simple_desc')" :class="form.simple_desc_row == '2' ? 'text-line-2' : 'text-line-1'" :style="simple_desc">{{ item.simple_desc }}</view>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('plugins_view_icon') && !isEmpty(item.plugins_view_icon_data)" class="flex-row gap-5 align-c">
|
||||
<view v-for="(icon_data, icon_index) in item.plugins_view_icon_data" :key="icon_index" class="radius text-size-xsss padding-horizontal-xs" :style="{ background: icon_data.bg_color, color: icon_data.color, border: '1rpx solid' + (!isEmpty(icon_data.br_color) ? icon_data.br_color : icon_data.bg_color) }">{{ icon_data.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!['3', '4', '5'].includes(form.theme)" class="flex-col gap-5">
|
||||
<view :class="[form.is_price_solo == '1' ? 'flex-row align-c nowrap' : 'flex-col gap-5']">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="'color:' + new_style.shop_price_color">
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('original_price') && !isEmpty(item.min_original_price)" class="text-size-xss flex-row">
|
||||
<!-- <image v-if="form.static_img.length > 0" class="original-price-left" :src="form.static_img[0].url" model="widthFix"></image> -->
|
||||
<text :class="['original-price text-line-1', { 'flex-1': form.is_price_solo == '1' }]" :style="original_price">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<block v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</block>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row jc-sb align-e">
|
||||
<view>
|
||||
<view v-if="show_content" class="flex-row align-c text-size-xss">
|
||||
<view v-if="is_show('sales_count') && !isEmpty(item.sales_count)" class="pr-5" :style="sold_number_style">已售{{ item.sales_count || 0 }}件</view>
|
||||
<!-- <view v-if="is_show('sales_count')" :class="['pr-5', {'br-r-e': is_show('sales_count') && is_show('4')}]" :style="sold_number_style>已售{{ item.sales_count }}件</view> -->
|
||||
<!-- <view v-if="is_show('4')" class="pl-5" :style="score_style">评分0</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(form.is_shop_show == '1' && form.shop_button_effect == '1' && item.is_error == 0) || (form.is_shop_show == '1' && form.shop_button_effect == '0')" class="pr" :data-index="index" @tap.stop="goods_button_event">
|
||||
<block v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + ('color:' + new_style.shop_button_text_color)">{{ form.shop_button_text }}</view>
|
||||
</block>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :style="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
<view v-if="form.shop_button_effect == '1'" class="cart-badge-icon pa badge-style">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="flex-row align-c jc-sb">
|
||||
<view class="flex-row align-c nowrap">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="'color:' + new_style.shop_price_color">
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('original_price') && !isEmpty(item.min_original_price)" class="text-size-xss flex-row">
|
||||
<!-- <image v-if="form.static_img.length > 0" class="original-price-left" :src="form.static_img[0].url" model="widthFix"></image> -->
|
||||
<text :class="['original-price text-line-1', { 'flex-1': form.is_price_solo == '1' }]" :style="original_price">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<block v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</block>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(form.is_shop_show == '1' && form.shop_button_effect == '1' && item.is_error == 0) || (form.is_shop_show == '1' && form.shop_button_effect == '0')" class="pr" :data-index="index" @tap.stop="goods_button_event">
|
||||
<block v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + ('color:' + new_style.shop_button_text_color)">{{ form.shop_button_text }}</view>
|
||||
</block>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :style="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
<view v-if="form.shop_button_effect == '1'" class="cart-badge-icon pa badge-style">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<swiper circular="true" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :next-margin="new_style.rolling_fashion == 'translation' ? '-' + content_outer_spacing_magin : '0rpx'" :display-multiple-items="slides_per_group" :style="{ width: '100%', height: new_style.content_outer_height * new_scale + 'px' }">
|
||||
<swiper-item v-for="(item1, index1) in shop_content_list" :key="index1">
|
||||
<view class="flex-row wh-auto ht-auto" :style="onter_style">
|
||||
<view v-for="(item, index) in item1.split_list" :key="index" class="pr oh" :style="layout_style" :data-index="index1" :data-split-index="index" :data-value="item.goods_url" @tap.stop="url_event">
|
||||
<view :class="layout_type" :style="layout_img_style">
|
||||
<block v-if="!isEmpty(item)">
|
||||
<view class="oh pr" :class="'flex-img' + theme">
|
||||
<view v-if="!isEmpty(item.new_cover)" :class="'flex-img' + theme">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="content_img_radius" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-else :class="'flex-img' + theme">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="content_img_radius" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</block>
|
||||
<view v-if="is_show('title') || is_show('simple_desc') || is_show('price') || is_show('plugins_view_icon') || is_show('original_price') || form.is_shop_show == '1'" class="flex-col flex-1 jc-sb content gap-10" :style="content_style">
|
||||
<view class="flex-col gap-10 top-title">
|
||||
<view v-if="is_show('title') || (['0', '1', '2', '3', '5'].includes(theme) && is_show('simple_desc'))" class="flex-col" :style="{ gap: new_style.title_simple_desc_spacing * 2 + 'rpx' }">
|
||||
<view v-if="is_show('title')" :class="text_line" :style="title_style">{{ item.title }}</view>
|
||||
<view v-if="['0', '1', '2', '3', '5'].includes(theme) && is_show('simple_desc')" :class="form.simple_desc_row == '2' ? 'text-line-2' : 'text-line-1'" :style="simple_desc">{{ item.simple_desc }}</view>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('plugins_view_icon') && !isEmpty(item.plugins_view_icon_data)" class="flex-row gap-5 align-c">
|
||||
<view v-for="(icon_data, icon_index) in item.plugins_view_icon_data" :key="icon_index" class="radius text-size-xsss padding-horizontal-xs" :style="{ background: icon_data.bg_color, color: icon_data.color, border: '1rpx solid' + (!isEmpty(icon_data.br_color) ? icon_data.br_color : icon_data.bg_color) }">{{ icon_data.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row align-c jc-sb">
|
||||
<view class="flex-row align-c nowrap">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="'color:' + new_style.shop_price_color">
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('original_price') && !isEmpty(item.min_original_price)" class="text-size-xss flex">
|
||||
<!-- <image v-if="form.static_img.length > 0" class="original-price-left" :src="form.static_img[0].url" model="widthFix"></image> -->
|
||||
<text :class="['original-price text-line-1', { 'flex-1': form.is_price_solo == '1' }]" :style="original_price">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<block v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</block>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(form.is_shop_show == '1' && form.shop_button_effect == '1' && item.is_error == 0) || (form.is_shop_show == '1' && form.shop_button_effect == '0')" class="pr" :data-index="index1" :data-split-index="index" @tap.stop="goods_button_event">
|
||||
<block v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + ('color:' + new_style.shop_button_text_color)">{{ form.shop_button_text }}</view>
|
||||
</block>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :style="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
<view v-if="form.shop_button_effect == '1'" class="cart-badge-icon pa badge-style">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty, common_styles_computer, common_img_computer, gradient_handle, padding_computer, radius_computer, background_computer, border_computer, box_shadow_computer, old_margin, margin_computer } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import subscriptIndex from '@/components/diy/modules/subscript/index.vue';
|
||||
import componentBadge from '@/components/badge/badge';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
componentBadge,
|
||||
subscriptIndex
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propIsCommonStyle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propDiyIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
propIsCartParaCurve: false,
|
||||
list: [],
|
||||
content_radius: '', // 圆角设置
|
||||
content_img_radius: '', // 图片圆角设置
|
||||
content_padding: '', // 内边距设置
|
||||
theme: '', // 选择的风格
|
||||
content_outer_spacing: '', // 商品间距
|
||||
content_outer_spacing_magin: '', // 商品间距
|
||||
// 最外层不同风格下的显示
|
||||
outer_class: '',
|
||||
onter_style: '',
|
||||
// 不同风格下的样式
|
||||
layout_type: '',
|
||||
layout_style: '',
|
||||
layout_img_style: '',
|
||||
content_style: '', // 内容区域的样式
|
||||
show_content: false, // 显示除标题外的其他区域
|
||||
text_line: '', // 超过多少行隐藏
|
||||
style_container: '', // 公共样式
|
||||
style_img_container: '',
|
||||
shop_content_list: [],
|
||||
slides_per_group: 1,
|
||||
// 内容样式
|
||||
title_style: '',
|
||||
price_style: '',
|
||||
sold_number_style: '',
|
||||
score_style: '',
|
||||
button_style: '',
|
||||
simple_desc: '',
|
||||
price_symbol: '',
|
||||
price_unit: '',
|
||||
original_price: '',
|
||||
// 按钮背景色
|
||||
button_gradient: '',
|
||||
// 图片大小
|
||||
img_size: '',
|
||||
new_scale: 1,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
},
|
||||
propValue(new_value, old_value) {
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content || null;
|
||||
const new_style = this.propValue.style || null;
|
||||
if (new_form != null && new_style != null) {
|
||||
let new_list = [];
|
||||
// 指定商品并且指定商品数组不为空
|
||||
if (!isEmpty(new_form.data_list) && new_form.data_type == '0') {
|
||||
new_list = new_form.data_list.map((item) => ({
|
||||
...item.data,
|
||||
title: !isEmpty(item.new_title) ? item.new_title : item.data.title,
|
||||
new_cover: item.new_cover,
|
||||
}));
|
||||
} else if (!isEmpty(new_form.data_auto_list) && new_form.data_type == '1') {
|
||||
// 筛选商品并且筛选商品数组不为空
|
||||
new_list = new_form.data_auto_list;
|
||||
}
|
||||
// 最外层不同风格下的显示
|
||||
const flex = ['0', '2', '6'].includes(new_form.theme) ? 'flex-col ' : 'flex-row ';
|
||||
const wrap = new_form.theme == '5' ? '' : 'flex-wrap ';
|
||||
const background = ['6'].includes(new_form.theme) ? 'bg-white ' : '';
|
||||
const button_gradient = gradient_handle(new_style.shop_button_color, '180deg');
|
||||
// 默认数据
|
||||
const product_style_list = [
|
||||
{ name: '单列展示', value: '0', width: 110, height: 120 },
|
||||
{ name: '大图展示', value: '2', width: 166, height: 166 },
|
||||
{ name: '无图模式', value: '6', width: 0, height: 0 },
|
||||
{ name: '两列展示(纵向)', value: '1', width: 180, height: 180 },
|
||||
{ name: '两列展示(横向)', value: '4', width: 70, height: 70 },
|
||||
{ name: '三列展示', value: '3', width: 116, height: 114 },
|
||||
{ name: '左右滑动展示', value: '5', width: 0, height: 0 },
|
||||
];
|
||||
const scale = sys_width / 390;
|
||||
let img_style = ``;
|
||||
if (['0', '4'].includes(new_form.theme)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_width == 'number') {
|
||||
img_style += `width: ${ new_style.content_img_width * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_form.theme);
|
||||
if (list.length > 0) {
|
||||
img_style += `width: ${ list[0].width * scale }px;`;
|
||||
} else {
|
||||
img_style += 'width: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!['5', '6'].includes(new_form.theme)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_height == 'number') {
|
||||
img_style += `height: ${ new_style.content_img_height * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_form.theme);
|
||||
if (list.length > 0) {
|
||||
img_style += `height: ${ list[0].height * scale }px;`;
|
||||
} else {
|
||||
img_style += 'height: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
outer_class: flex + wrap + background + 'oh',
|
||||
list: new_list,
|
||||
new_scale: scale,
|
||||
content_radius: radius_computer(new_style.shop_radius), // 圆角设置
|
||||
content_img_radius: radius_computer(new_style.shop_img_radius), // 图片圆角设置
|
||||
content_padding: padding_computer(new_style.shop_padding) + 'box-sizing: border-box;', // 内边距设置
|
||||
theme: new_form.theme, // 选择的风格
|
||||
content_outer_spacing: new_style.content_outer_spacing, // 商品间距
|
||||
content_outer_spacing_magin: new_style.content_outer_spacing * 2 + 'rpx',
|
||||
onter_style: new_form.theme == '6' ? radius_computer(new_style.shop_radius) : `gap: ${new_style.content_outer_spacing * 2 + 'rpx'};`,
|
||||
// 不同风格下的样式
|
||||
layout_type: ['0', '4'].includes(new_form.theme) ? 'flex-row wh-auto ht-auto oh' : 'flex-col wh-auto ht-auto oh',
|
||||
layout_style: this.get_layout_style(new_style, new_form),
|
||||
layout_img_style: this.get_layout_img_style(new_style, new_form),
|
||||
content_style: this.get_content_style(new_style, new_form), // 内容区域的样式
|
||||
show_content: ['0', '1', '2'].includes(new_form.theme), // 显示除标题外的其他区域
|
||||
text_line: this.get_text_line(new_form), // 超过多少行隐藏
|
||||
style_container: this.propIsCommonStyle ? common_styles_computer(new_style.common_style) : '', // 公共样式
|
||||
style_img_container: this.propIsCommonStyle ? common_img_computer(new_style.common_style, this.propIndex) : '', // 图片样式
|
||||
// 内容样式设置
|
||||
button_gradient: button_gradient,
|
||||
title_style: this.trends_config(new_style, 'title', 'title', new_form),
|
||||
price_style: this.trends_config(new_style, 'price'),
|
||||
sold_number_style: this.trends_config(new_style, 'sold_number'),
|
||||
score_style: this.trends_config(new_style, 'score'),
|
||||
button_style: this.trends_config(new_style, 'button', 'buy_button') + button_gradient,
|
||||
simple_desc: this.trends_config(new_style, 'simple_desc', 'desc', new_form),
|
||||
price_symbol: !isEmpty(new_style.shop_price_symbol_color) ? this.trends_config(new_style, 'price_symbol') : 'font-size: 18rpx;color: #EA3323;' ,
|
||||
price_unit: !isEmpty(new_style.shop_price_unit_color) ? this.trends_config(new_style, 'price_unit') : 'font-size: 18rpx;color: #EA3323;',
|
||||
original_price: this.trends_config(new_style, 'original_price'),
|
||||
shop_content_list: this.get_shop_content_list(new_list, new_form, new_style),
|
||||
slides_per_group: new_style.rolling_fashion == 'translation' ? new_form.carousel_col : 1,
|
||||
img_size: img_style,
|
||||
});
|
||||
}
|
||||
},
|
||||
get_shop_content_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
get_text_line(form) {
|
||||
let line = '';
|
||||
if (['1', '6'].includes(form.theme)) {
|
||||
line = 'text-line-1';
|
||||
} else if (['0', '2', '3', '4', '5'].includes(form.theme)) {
|
||||
line = 'text-line-2';
|
||||
}
|
||||
return line;
|
||||
},
|
||||
// 不同风格下的样式
|
||||
get_layout_style(new_style, form) {
|
||||
const { shop_margin = old_margin } = new_style;
|
||||
const radius = form.theme == '6' ? '' : radius_computer(new_style.shop_radius);
|
||||
const style = form.theme != '6' ? gradient_handle(new_style?.shop_color_list || [], new_style?.shop_direction || '') + margin_computer(shop_margin) + border_computer(new_style) + box_shadow_computer(new_style) : '';
|
||||
let size_style = ``;
|
||||
const shop_left_right_width = shop_margin.margin_left + shop_margin.margin_right;
|
||||
if (['1', '4'].includes(form.theme)) {
|
||||
size_style = `width: calc((100% - ${new_style.content_outer_spacing * 2 + (shop_left_right_width * 4) + 'rpx'}) / 2);`;
|
||||
} else if (form.theme == '3') {
|
||||
size_style = `width: calc((100% - ${new_style.content_outer_spacing * 4 + (shop_left_right_width * 6) + 'rpx'}) / 3);`;
|
||||
} else if (form.theme == '5') {
|
||||
// 如果不是平移的时候执行
|
||||
if (new_style.rolling_fashion != 'translation') {
|
||||
size_style = `width: ${this.get_multicolumn_columns_width(new_style, form)};min-width: ${this.get_multicolumn_columns_width(new_style, form)};height: ${new_style.content_outer_height * (sys_width / 390) + 'px'};`;
|
||||
} else {
|
||||
size_style = `margin-right: ${ (new_style.content_outer_spacing * 2) + (shop_margin.margin_right * 2) }rpx;width: 100%;height: 100%;`;
|
||||
}
|
||||
} else if (form.theme == '0') {
|
||||
size_style = `width: calc(100% - ${ shop_left_right_width }px);`;
|
||||
}
|
||||
return `${radius} ${ style } ${size_style}`;
|
||||
},
|
||||
get_layout_img_style(new_style, form) {
|
||||
const padding = ['0', '4'].includes(form.theme) ? padding_computer(new_style.shop_padding) + 'box-sizing: border-box;' : '';
|
||||
const data = {
|
||||
background_img_style: new_style?.shop_background_img_style || '',
|
||||
background_img: new_style?.shop_background_img || '',
|
||||
}
|
||||
const background = form.theme != '6' ? background_computer(data) : '';
|
||||
return `${padding} ${background}`;
|
||||
},
|
||||
get_multicolumn_columns_width(new_style, form) {
|
||||
const { carousel_col } = form;
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.content_outer_spacing * (carousel_col - 1)) / carousel_col;
|
||||
return `calc(${100 / carousel_col}% - ${gap * 2}rpx)`;
|
||||
},
|
||||
get_content_style(new_style, form) {
|
||||
const spacing_value = new_style.content_spacing;
|
||||
let spacing = '';
|
||||
if (['0', '4'].includes(form.theme)) {
|
||||
spacing = `margin-left: ${spacing_value * 2}rpx;`;
|
||||
} else {
|
||||
spacing = padding_computer(new_style.shop_padding) + 'box-sizing: border-box;';
|
||||
}
|
||||
return `${spacing}`;
|
||||
},
|
||||
// 判断是否显示对应的内容
|
||||
is_show(index) {
|
||||
return this.form.is_show.includes(index);
|
||||
},
|
||||
// 根据传递的参数,从对象中取值
|
||||
trends_config(new_style, key, type, new_form) {
|
||||
return this.style_config(new_style[`shop_${key}_typeface`], new_style[`shop_${key}_size`], new_style[`shop_${key}_color`], type, new_form);
|
||||
},
|
||||
// 根据传递的值,显示不同的内容
|
||||
style_config(typeface, size, color, type, new_form) {
|
||||
let style = `font-weight:${typeface}; font-size: ${size * 2}rpx;`;
|
||||
if (type == 'title') {
|
||||
if (['1', '6'].includes(new_form.theme)) {
|
||||
style += `line-height: ${size * 2}rpx;height: ${size * 2}rpx;color: ${color};`;
|
||||
} else if (['0', '2', '3', '4', '5'].includes(new_form.theme)) {
|
||||
style += `line-height: ${size > 0 ? (size + 3) * 2 : 0}rpx;height: ${size > 0 ? (size + 3) * 4 : 0}rpx;color: ${color};`;
|
||||
}
|
||||
} else if (type == 'desc') {
|
||||
if (new_form.simple_desc_row == '2') {
|
||||
style += `line-height: ${size > 0 ? (size + 3) * 2 : 0}rpx;height: ${size > 0 ? (size + 3) * 4 : 0}rpx;color: ${color};`;
|
||||
} else {
|
||||
style += `line-height: ${size * 2}rpx;height: ${size * 2}rpx;color: ${color};`;
|
||||
}
|
||||
} else {
|
||||
if (type != 'buy_button') {
|
||||
style += `color: ${color};`;
|
||||
}
|
||||
}
|
||||
return style;
|
||||
},
|
||||
// icon标志显示样式
|
||||
icon_style(item) {
|
||||
let style = `background: ${item.bg_color};color: ${item.color};`;
|
||||
if (!isEmpty(item.br_color)) {
|
||||
style += `border: 2rpx solid ${item.br_color};`;
|
||||
} else {
|
||||
style += `border: 2rpx solid ${item.bg_color};`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
url_event(e) {
|
||||
let index = e.currentTarget.dataset.index || 0;
|
||||
let goods = this.list[index];
|
||||
let split_index = 0;
|
||||
if (this.theme == '5') {
|
||||
split_index = e.currentTarget.dataset.splitIndex || 0;
|
||||
goods = this.shop_content_list[index].split_list[split_index];
|
||||
}
|
||||
app.globalData.goods_data_cache_handle(goods.id, goods);
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
goods_button_event(e) {
|
||||
this.goods_cart_event(e);
|
||||
},
|
||||
// 加入购物车
|
||||
goods_cart_event(e) {
|
||||
let index = e.currentTarget.dataset.index || 0;
|
||||
let split_index = 0;
|
||||
let goods = this.list[index];
|
||||
if (this.theme == '5') {
|
||||
split_index = e.currentTarget.dataset.splitIndex || 0;
|
||||
goods = this.shop_content_list[index].split_list[split_index];
|
||||
}
|
||||
if (this.form.shop_button_effect == '0') {
|
||||
app.globalData.goods_data_cache_handle(goods.id, goods);
|
||||
|
||||
app.globalData.url_open(goods.goods_url);
|
||||
} else {
|
||||
// 开启购物车抛物线效果则展示提示操作
|
||||
let is_success_tips = this.propIsCartParaCurve ? 0 : 1;
|
||||
this.$emit(
|
||||
'goods_buy_event',
|
||||
this.propDiyIndex,
|
||||
goods,
|
||||
{
|
||||
buy_event_type: 'cart',
|
||||
is_direct_cart: 1,
|
||||
is_success_tips: is_success_tips,
|
||||
},
|
||||
{
|
||||
index: index,
|
||||
split_index: split_index,
|
||||
pos: e,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
// 加入购物车成功回调
|
||||
goods_cart_back_event(e) {
|
||||
app.globalData.showToast('加入成功', 'success');
|
||||
// 增加数量
|
||||
var { index, split_index } = e.back_data;
|
||||
let new_data = this.list;
|
||||
let goods = new_data[index];
|
||||
if (this.theme == '5') {
|
||||
new_data = this.shop_content_list;
|
||||
goods = new_data[index][split_index];
|
||||
}
|
||||
goods['user_cart_count'] = parseInt(goods['user_cart_count'] || 0) + parseInt(e.stock);
|
||||
if (goods['user_cart_count'] > 99) {
|
||||
goods['user_cart_count'] = '99+';
|
||||
}
|
||||
if (this.theme != '5') {
|
||||
new_data[index] = goods;
|
||||
this.setData({
|
||||
list: new_data,
|
||||
});
|
||||
} else {
|
||||
new_data[index][split_index] = goods;
|
||||
this.setData({
|
||||
shop_content_list: new_data,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.identifying {
|
||||
font-size: 18rpx;
|
||||
}
|
||||
.original-price {
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
.flex-img5 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
// .original-price-left {
|
||||
// width: 20rpx;
|
||||
// height: 28rpx;
|
||||
// }
|
||||
.br-b-e {
|
||||
border-bottom: 2rpx solid #eee;
|
||||
}
|
||||
.badge-style {
|
||||
top: -20rpx;
|
||||
right: 10rpx;
|
||||
}
|
||||
</style>
|
||||
253
components/diy/goods-tabs.vue
Normal file
253
components/diy/goods-tabs.vue
Normal file
@@ -0,0 +1,253 @@
|
||||
<template>
|
||||
<view class="goods-tabs ou" :class="'goods-tabs-' + propKey" :style="style_container">
|
||||
<view class="ou" :style="style_img_container">
|
||||
<componentDiyModulesTabsView :propKey="propKey" :propValue="goods_tabs" :propIsTop="top_up == '1'" :propTop="sticky_top" :propStyle="tabs_style" :propsTabsContainer="tabs_container" :propsTabsImgContainer="tabs_img_container" :propCustomNavHeight="propIsTabsUseSafeDistance ? (propCustomNavHeight * 2 + 'rpx') : '0rpx'" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" :propTabsBackground="tabs_background" @onTabsTap="tabs_click_event"></componentDiyModulesTabsView>
|
||||
<view :style="shop_margin_top">
|
||||
<view :style="shop_container">
|
||||
<view :style="shop_img_container">
|
||||
<componentGoodsList ref="diy_goods_list" :propKey="diy_key" :propDiyIndex="propDiyIndex" :propValue="goods_tabs" :propIsCommonStyle="false" @goods_buy_event="goods_buy_event"></componentGoodsList>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, margin_computer, background_computer, gradient_computer, isEmpty, old_border_and_box_shadow, old_margin, old_radius, old_padding, border_computer, box_shadow_computer, radius_computer } from '@/common/js/common/common.js';
|
||||
import componentDiyModulesTabsView from '@/components/diy/modules/tabs-view';
|
||||
import componentGoodsList from '@/components/diy/goods-list';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
components: {
|
||||
componentDiyModulesTabsView,
|
||||
componentGoodsList,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propCustomNavHeight: {
|
||||
type: Number,
|
||||
default: 33,
|
||||
},
|
||||
propScrollTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 顶部导航是否开启沉浸模式
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propDiyIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propIsTabsUseSafeDistance: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
goods_tabs: {},
|
||||
// 是否滑动置顶
|
||||
top_up: '0',
|
||||
tabs_top: 0,
|
||||
tabs_background: 'background:transparent',
|
||||
custom_nav_height: 33,
|
||||
diy_key: '',
|
||||
// 选项卡背景设置
|
||||
tabs_container: '',
|
||||
tabs_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
// 商品区域背景设置
|
||||
shop_margin_top: '',
|
||||
shop_container: '',
|
||||
shop_img_container: '',
|
||||
// #ifdef MP
|
||||
nav_safe_space: bar_height + 5,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
nav_safe_space: bar_height + 7,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
nav_safe_space: bar_height + 0,
|
||||
// #endif
|
||||
// 选项卡默认数据
|
||||
tabs_index: 0,
|
||||
sticky_top: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propScrollTop(newVal) {
|
||||
if (newVal + this.sticky_top + this.custom_nav_height > this.tabs_top + this.nav_safe_space && this.top_up == '1') {
|
||||
let new_style = this.propValue.style || {};
|
||||
let tabs_bg = new_style.common_style.color_list;
|
||||
let new_tabs_background = '';
|
||||
if (tabs_bg.length > 0 && (tabs_bg[0].color || null) != null) {
|
||||
new_tabs_background = gradient_computer(new_style.common_style);
|
||||
}
|
||||
let new_tabs_background_img = background_computer(new_style.common_style);
|
||||
if (new_tabs_background_img.length > 0) {
|
||||
new_tabs_background_img += 'background-position: top left;';
|
||||
}
|
||||
this.tabs_background = (new_tabs_background.length > 0 ? new_tabs_background : 'background:#fff;') + new_tabs_background_img;
|
||||
} else {
|
||||
this.tabs_background = 'background:transparent';
|
||||
}
|
||||
},
|
||||
propTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.setData({
|
||||
diy_key: val,
|
||||
});
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const self = this;
|
||||
setTimeout(() => {
|
||||
self.getTop();
|
||||
});
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// 获取自定义导航栏高度
|
||||
this.setData({
|
||||
custom_nav_height: this.propCustomNavHeight,
|
||||
});
|
||||
// #endif
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_content = new_data.content || {};
|
||||
const new_style = new_data.style || {};
|
||||
const new_tabs_data = new_data.content.tabs_list[this.tabs_index] || {};
|
||||
// 产品的值
|
||||
new_data.content.data_type = new_tabs_data.data_type;
|
||||
new_data.content.category = new_tabs_data.category;
|
||||
new_data.content.brand = new_tabs_data.brand;
|
||||
new_data.content.number = new_tabs_data.number;
|
||||
new_data.content.sort = new_tabs_data.sort;
|
||||
new_data.content.sort_rules = new_tabs_data.sort_rules;
|
||||
new_data.content.data_list = new_tabs_data.data_list;
|
||||
new_data.content.data_auto_list = new_tabs_data.data_auto_list;
|
||||
// 公共样式
|
||||
const common_style = new_style.common_style;
|
||||
let tabs_style_obj = {
|
||||
padding_top: common_style.padding_top - this.propCustomNavHeight < 0 ? 0 : common_style.padding_top - this.propCustomNavHeight,
|
||||
padding_left: common_style.padding_left,
|
||||
padding_right: common_style.padding_right,
|
||||
};
|
||||
let new_tabs_style = padding_computer(tabs_style_obj) + `position:relative;left: -${tabs_style_obj.padding_left * 2}rpx;right: -${tabs_style_obj.padding_right * 2}rpx;width:100%;`;
|
||||
// 如果是历史数据的话,就执行默认添加下边距
|
||||
if (isEmpty(new_style.tabs_padding)) {
|
||||
new_tabs_style += 'padding-bottom: 20rpx;';
|
||||
}
|
||||
const { tabs_bg_color_list = [], tabs_bg_direction = '', tabs_bg_background_img_style = '', tabs_bg_background_img = [], tabs_radius = old_radius, tabs_padding = old_padding, shop_content_color_list = [], shop_content_direction = '', shop_content_background_img_style = '', shop_content_background_img = [], shop_content_margin = old_margin, shop_content_padding = old_padding, shop_content_radius = old_radius } = new_style;
|
||||
// 选项卡背景设置
|
||||
const tabs_data = {
|
||||
color_list: tabs_bg_color_list,
|
||||
direction: tabs_bg_direction,
|
||||
background_img_style: tabs_bg_background_img_style,
|
||||
background_img: tabs_bg_background_img,
|
||||
};
|
||||
// 商品区域背景设置
|
||||
const shop_content_data = {
|
||||
color_list: shop_content_color_list,
|
||||
direction: shop_content_direction,
|
||||
background_img_style: shop_content_background_img_style,
|
||||
background_img: shop_content_background_img,
|
||||
};
|
||||
const shop_content = new_style?.shop_content || old_border_and_box_shadow;
|
||||
const tabs_content = new_style?.tabs_content || old_border_and_box_shadow;
|
||||
this.setData({
|
||||
top_up: new_content.tabs_top_up,
|
||||
sticky_top: this.propTop + (new_style?.tabs_margin?.margin_top || 0),
|
||||
goods_tabs: new_data,
|
||||
style_container: common_styles_computer(common_style),
|
||||
style_img_container: common_img_computer(common_style, this.propIndex),
|
||||
tabs_style: new_tabs_style,
|
||||
tabs_sliding_fixed_bg: gradient_computer(tabs_data),
|
||||
tabs_container: gradient_computer(tabs_data) + radius_computer(tabs_radius) + margin_computer(new_style?.tabs_margin || old_margin) + border_computer(tabs_content) + box_shadow_computer(tabs_content) + 'overflow: hidden;',
|
||||
tabs_img_container: background_computer(tabs_data) + padding_computer(tabs_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
shop_margin_top: 'margin-top:' + (new_style?.shop_content_spacing || 0) * 2 + 'rpx;',
|
||||
shop_container: gradient_computer(shop_content_data) + margin_computer(shop_content_margin) + radius_computer(shop_content_radius) + box_shadow_computer(shop_content) + border_computer(shop_content) + 'overflow: hidden;',
|
||||
shop_img_container: background_computer(shop_content_data) + padding_computer(shop_content_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
});
|
||||
},
|
||||
tabs_click_event(index) {
|
||||
let new_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
new_data.content.data_type = new_data.content.tabs_list[index].data_type;
|
||||
new_data.content.category = new_data.content.tabs_list[index].category;
|
||||
new_data.content.brand = new_data.content.tabs_list[index].brand;
|
||||
new_data.content.number = new_data.content.tabs_list[index].number;
|
||||
new_data.content.sort = new_data.content.tabs_list[index].sort;
|
||||
new_data.content.sort_rules = new_data.content.tabs_list[index].sort_rules;
|
||||
new_data.content.data_list = new_data.content.tabs_list[index].data_list;
|
||||
new_data.content.data_auto_list = new_data.content.tabs_list[index].data_auto_list;
|
||||
this.setData({
|
||||
tabs_index: index,
|
||||
goods_tabs: new_data,
|
||||
diy_key: Math.random(),
|
||||
});
|
||||
},
|
||||
// 获取商品距离顶部的距离
|
||||
getTop() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.goods-tabs-' + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_style = new_data.style || {};
|
||||
this.setData({
|
||||
tabs_top: res.top - (new_style.common_style?.margin_top || 0),
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
goods_buy_event(index, goods = {}, params = {}, back_data = null) {
|
||||
this.$emit('goods_buy_event', index, goods, params, back_data);
|
||||
},
|
||||
goods_cart_back_event(e) {
|
||||
if ((this.$refs.diy_goods_list || null) != null) {
|
||||
this.$refs.diy_goods_list.goods_cart_back_event(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
420
components/diy/header.vue
Normal file
420
components/diy/header.vue
Normal file
@@ -0,0 +1,420 @@
|
||||
<template>
|
||||
<view v-if="(propValue || null) !== null" class="header-container">
|
||||
<view class="header-around wh-auto" :style="roll_style + position">
|
||||
<view class="wh-auto" :style="roll_img_style">
|
||||
<view class="wh-auto ht-auto pa up_slide_bg" :style="up_slide_style">
|
||||
<view class="wh-auto ht-auto" :style="up_slide_img_style"></view>
|
||||
</view>
|
||||
<view :style="top_content_style">
|
||||
<view class="header-content flex-row align-s">
|
||||
<view class="model-top flex-1 mt-1">
|
||||
<view class="roll pr z-i">
|
||||
<view class="model-head pr padding-left-main padding-right-main" style="box-sizing: border-box">
|
||||
<view class="flex-col" :style="'gap:' + data_alone_row_space">
|
||||
<view class="model-head-content flex-row align-c jc-sb gap-16 wh-auto pr" :style="header_style">
|
||||
<!-- 支付宝小程序自带返回按钮,这里就不给返回按钮了,这里给留出一点空间就行 -->
|
||||
<!-- #ifndef MP-ALIPAY -->
|
||||
<view v-if="!is_tabbar_pages" class="z-i dis-inline-block margin-top-xs" @tap="top_nav_left_back_event">
|
||||
<iconfont name="icon-arrow-left" size="40rpx" propContainerDisplay="flex" :color="form.style.left_back_btn_color || '#333'"></iconfont>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<view class="dis-inline-block padding-left-sm"></view>
|
||||
<!-- #endif -->
|
||||
<view v-if="['1', '2', '3'].includes(form.content.theme)" class="flex-1">
|
||||
<view class="flex-row align-c jc-c ht-auto gap-16" :class="position_class" :style="text_style + 'justify-content:' + form.content.indicator_location || 'center'">
|
||||
<template v-if="['2', '3'].includes(form.content.theme)">
|
||||
<view v-if="form.content.logo.length > 0" class="logo-outer-style re flex-row align-c">
|
||||
<template v-if="form.style.up_slide_logo && form.style.up_slide_logo.length > 0">
|
||||
<!-- 有上滑logo的处理逻辑 -->
|
||||
<view v-if="(propScrollTop - 5) / (header_top + 33) < 1" class="logo-style" :style="up_slide_old_logo_style">
|
||||
<image class="logo-style" :src="form.content.logo[0].url" mode="heightFix" />
|
||||
</view>
|
||||
<view :class="['logo-style left-0', { pa: (propScrollTop - 5) / (header_top + 33) < 1 }]" :style="'opacity:0;' + up_slide_opacity">
|
||||
<image class="logo-style" :src="form.style.up_slide_logo[0].url" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 没有上滑logo的处理逻辑 -->
|
||||
<image class="logo-style" :src="form.content.logo[0].url" mode="heightFix" />
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="['1', '2', '3'].includes(form.content.theme) && !isEmpty(form.content.title)">{{ form.content.title }}</view>
|
||||
<template v-if="['3'].includes(form.content.theme) && !is_search_alone_row">
|
||||
<view class="flex-1 fw-n">
|
||||
<componentDiySearch :propValue="form" :propIsPageSettings="true"></componentDiySearch>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="['4', '5'].includes(form.content.theme)" class="flex-1 flex-row align-c">
|
||||
<view v-if="form.content.positioning_name_float !== '1'" class="flex-row align-c gap-2">
|
||||
<view :style="location_margin">
|
||||
<component-choice-location :propLocationContainerStyle="style_location_container" :propLocationImgContainerStyle="style_location_img_container" :propBaseColor="location_color" :propTextDefaultName="form.content.positioning_name" :propIsLeftIconArrow="form.content.is_location_left_icon_show == '1'" :propLeftImgValue="form.content.location_left_img" :propLeftIconValue="'icon-' + form.content.location_left_icon" :propIconLocationSize="location_left_size" :propIconArrowSize="location_right_size" :propIsRightIconArrow="form.content.is_location_right_icon_show == '1'" :propRightImgValue="form.content.location_right_img" :propRightIconValue="'icon-' + form.content.location_right_icon" :propTextMaxWidth="location_name_style" propContainerDisplay="flex" @onBack="choice_location_back"></component-choice-location>
|
||||
</view>
|
||||
</view>
|
||||
<template v-if="['5'].includes(form.content.theme) && !is_search_alone_row">
|
||||
<view class="flex-1">
|
||||
<componentDiySearch :propValue="form" :propIsPageSettings="true" :propLocationMargin="location_margin" propSearchType="header" :propLocationContainerStyle="style_location_container" :propLocationImgContainerStyle="style_location_img_container" :propBaseColor="location_color" :propIconLocationSize="location_left_size" :propIconArrowSize="location_right_size" @onBack="choice_location_back"></componentDiySearch>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<view v-if="!isEmpty(form.content.icon_setting) && !is_icon_alone_row" class="flex-row align-c z-i" :class="['1'].includes(form.content.theme) ? 'right-0' : ''" :style="{ gap: form.style.img_space * 2 + 'rpx' }">
|
||||
<view v-for="(item, index) in form.content.icon_setting" :key="index" class="pr" :style="{ width: form.style.img_size * 2 + 'rpx', height: form.style.img_size * 2 + 'rpx' }" :data-value="item.link.page" @tap="url_event">
|
||||
<imageEmpty v-if="item.img.length > 0" :propImageSrc="item.img[0].url" :propErrorStyle="'width: ' + Number(form.style.img_size) * 2 + 'rpx;height:' + Number(form.style.img_size) * 2 + 'rpx;'"></imageEmpty>
|
||||
<iconfont v-else :name="'icon-' + item.icon" :size="form.style.img_size * 2 + 'rpx'" :color="form.style.img_color" propContainerDisplay="flex"></iconfont>
|
||||
<view v-if="!isEmpty(item.badge) && item.badge !== 0" class="pa badge-style">
|
||||
<component-badge :propNumber="item.badge || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="is_search_alone_row || is_icon_alone_row" class="model-head-content flex-row align-c gap-16">
|
||||
<template v-if="['3', '5'].includes(form.content.theme) && is_search_alone_row">
|
||||
<view class="flex-1">
|
||||
<componentDiySearch :propValue="form" :propIsPageSettings="true" :propLocationMargin="location_margin" propSearchType="header" :propLocationContainerStyle="style_location_container" :propLocationImgContainerStyle="style_location_img_container" :propBaseColor="location_color" :propIconLocationSize="location_left_size" :propIconArrowSize="location_right_size" @onBack="choice_location_back"></componentDiySearch>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="!isEmpty(form.content.icon_setting) && is_icon_alone_row" class="flex-row align-c z-i" :class="['1'].includes(form.content.theme) ? 'right-0' : ''" :style="{ gap: form.style.img_space * 2 + 'rpx' }">
|
||||
<view v-for="(item, index) in form.content.icon_setting" :key="index" class="pr" :style="{ width: form.style.img_size * 2 + 'rpx', height: form.style.img_size * 2 + 'rpx' }" :data-value="item.link.page" @tap="url_event">
|
||||
<imageEmpty v-if="item.img.length > 0" :propImageSrc="item.img[0].url" :propErrorStyle="'width: ' + Number(form.style.img_size) * 2 + 'rpx;height:' + Number(form.style.img_size) * 2 + 'rpx;'"></imageEmpty>
|
||||
<iconfont v-else :name="'icon-' + item.icon" :size="form.style.img_size * 2 + 'rpx'" :color="form.style.img_color" propContainerDisplay="flex"></iconfont>
|
||||
<view v-if="!isEmpty(item.badge) && item.badge !== 0" class="pa badge-style">
|
||||
<component-badge :propNumber="item.badge || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<block v-if="!is_immersion_model">
|
||||
<view v-if="!is_positon_realative" class="nav-seat" :style="top_content_style">
|
||||
<view :style="'height:' + (is_search_alone_row || is_icon_alone_row ? 'calc(132rpx + ' + data_alone_row_space + ');' : '66rpx;')"></view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- #ifndef H5 || MP-TOUTIAO -->
|
||||
<!-- <view v-if="is_positon_realative" class="wh-auto pf top-0 left-0 right-0" :style="roll_style">
|
||||
<view :style="top_content_style">
|
||||
<view :style="'height:' + (is_search_alone_row || is_icon_alone_row ? 'calc(132rpx + ' + data_alone_row_space + ');' : '66rpx;')"></view>
|
||||
</view>
|
||||
</view> -->
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentDiySearch from '@/components/diy/search';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty';
|
||||
import componentChoiceLocation from '@/components/choice-location/choice-location';
|
||||
import componentBadge from '@/components/badge/badge';
|
||||
import { isEmpty, background_computer, gradient_computer, margin_computer, padding_computer, radius_computer } from '@/common/js/common/common.js';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: [String, Number, Object],
|
||||
default: '',
|
||||
},
|
||||
// 滚动距离
|
||||
propScrollTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
componentDiySearch,
|
||||
imageEmpty,
|
||||
componentChoiceLocation,
|
||||
componentBadge,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
position: '',
|
||||
roll_style: '',
|
||||
text_style: '',
|
||||
header_style: 'max-width:100%',
|
||||
common_app_is_header_nav_fixed: 0,
|
||||
// 5,7,0 是误差,, 10 是下边距,66是高度,bar_height是不同小程序下的导航栏距离顶部的高度
|
||||
// #ifdef MP
|
||||
top_content_style: 'padding-top:' + (bar_height + 5) + 'px;padding-bottom:10px;',
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
top_content_style: 'padding-top:' + (bar_height + 7) + 'px;padding-bottom:10px;',
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
top_content_style: 'padding-top:' + bar_height + 'px;padding-bottom:10px;',
|
||||
// #endif
|
||||
is_positon_realative: false,
|
||||
// 顶部背景样式类别
|
||||
header_background_type: 'color_image',
|
||||
// #ifdef MP
|
||||
header_top: bar_height + 5 + 10 + 33,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
header_top: bar_height + 7 + 10 + 33,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
header_top: bar_height + 0 + 10 + 33,
|
||||
// #endif
|
||||
// 判断是否是沉浸模式
|
||||
is_immersion_model: false,
|
||||
up_slide_opacity: '',
|
||||
up_slide_old_logo_style: '',
|
||||
up_slide_style: '',
|
||||
up_slide_img_style: '',
|
||||
// 当前页面是否在底部菜单中
|
||||
is_tabbar_pages: app.globalData.is_tabbar_pages(),
|
||||
// 判断header的查询是否独行
|
||||
is_search_alone_row: false,
|
||||
is_icon_alone_row: false,
|
||||
data_alone_row_space: '0rpx',
|
||||
// 定位设置
|
||||
style_location_container: '',
|
||||
style_location_img_container: '',
|
||||
location_left_size: '24rpx',
|
||||
location_right_size: '24rpx',
|
||||
location_margin: '', // 悬浮之后有间距,所以要将margin设置成外padding
|
||||
location_color: '', // 定位颜色
|
||||
location_name_style: '', // 定位样式
|
||||
// 默认数据
|
||||
old_radius: { radius: 0, radius_top_left: 0, radius_top_right: 0, radius_bottom_left: 0, radius_bottom_right: 0 },
|
||||
old_padding: { padding: 0, padding_top: 0, padding_bottom: 0, padding_left: 0, padding_right: 0 },
|
||||
old_margin: { margin: 0, margin_top: 0, margin_bottom: 0, margin_left: 0, margin_right: 0 },
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听滚动距离
|
||||
propScrollTop(newVal) {
|
||||
const { up_slide_background_color_list, up_slide_background_direction, up_slide_background_img, up_slide_background_img_style, up_slide_display } = this.propValue.style || {};
|
||||
if (up_slide_display == '1') {
|
||||
// 渐变
|
||||
const gradient = { color_list: up_slide_background_color_list, direction: up_slide_background_direction };
|
||||
// 背景图
|
||||
const back = { background_img: up_slide_background_img, background_img_style: up_slide_background_img_style };
|
||||
const up_slide_opacity = 'opacity:' + ((newVal - 20) / this.header_top > 1 ? 1 : ((newVal - 20) / this.header_top).toFixed(2)) + ';';
|
||||
this.up_slide_opacity = up_slide_opacity;
|
||||
// 来的logo要比新的隐藏的快,所以要比原来的logo快一点
|
||||
this.up_slide_old_logo_style = 'opacity:' + ((newVal - 5) / this.header_top > 1 ? 0 : (1 - (newVal - 5) / this.header_top).toFixed(2)) + ';';
|
||||
// =0是大小误差
|
||||
this.up_slide_style = gradient_computer(gradient) + up_slide_opacity;
|
||||
this.up_slide_img_style = background_computer(back);
|
||||
}
|
||||
},
|
||||
propKey(val) {
|
||||
if ((this.propValue || null) !== null) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 判断是否有值初始化
|
||||
if ((this.propValue || null) !== null) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 判断是否为空
|
||||
isEmpty,
|
||||
// 初始化
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
let new_roll_style = '';
|
||||
let new_roll_img_style = '';
|
||||
const { header_background_img, header_background_img_style, header_background_color_list, header_background_direction, header_background_type, immersive_style } = new_style;
|
||||
if (header_background_type === 'color_image') {
|
||||
// 渐变
|
||||
const gradient = { color_list: header_background_color_list, direction: header_background_direction };
|
||||
// 背景图
|
||||
const back = { background_img: header_background_img, background_img_style: header_background_img_style };
|
||||
new_roll_style += gradient_computer(gradient);
|
||||
new_roll_img_style += background_computer(back);
|
||||
} else {
|
||||
new_roll_style += `background: transparent;`;
|
||||
}
|
||||
// 小程序下,获取小程序胶囊的宽度
|
||||
let menu_button_info = 'max-width:100%';
|
||||
let new_text_style = `font-weight:${new_style.header_background_title_typeface}; font-size: ${new_style.header_background_title_size * 2}rpx; color: ${new_style.header_background_title_color};`;
|
||||
// #ifndef MP-TOUTIAO
|
||||
// #ifdef MP
|
||||
// 判断是否有胶囊
|
||||
const is_current_single_page = app.globalData.is_current_single_page();
|
||||
// 如果有胶囊的时候,做处理
|
||||
if (is_current_single_page == 0) {
|
||||
const custom = uni.getMenuButtonBoundingClientRect();
|
||||
menu_button_info = `max-width:calc(100% - ${custom.width + 10}px);`;
|
||||
new_text_style += `right:-${custom.width + 10}px;`;
|
||||
}
|
||||
// #endif
|
||||
// #endif
|
||||
const { location_margin = this.old_margin } = new_style;
|
||||
this.setData({
|
||||
form: this.propValue,
|
||||
position: new_style.up_slide_display == '1' ? 'position:fixed;' : new_style.immersive_style === '1' ? 'position:absolute;' : 'position:relative;',
|
||||
is_positon_realative: new_style.up_slide_display == '1' ? false : true,
|
||||
roll_style: new_roll_style,
|
||||
roll_img_style: new_roll_img_style,
|
||||
text_style: new_text_style,
|
||||
position_class: new_content.indicator_location == 'center' ? `indicator-center` : '',
|
||||
header_style: menu_button_info,
|
||||
header_background_type: header_background_type,
|
||||
is_immersion_model: header_background_type !== 'color_image' && immersive_style == '1',
|
||||
data_alone_row_space: new_style.data_alone_row_space * 2 + 'rpx',
|
||||
is_search_alone_row: new_content.data_alone_row_value && new_content.data_alone_row_value.includes('search'),
|
||||
is_icon_alone_row: new_content.data_alone_row_value && new_content.data_alone_row_value.includes('icon'),
|
||||
style_location_container: this.get_style_location_container(new_style),
|
||||
style_location_img_container: this.get_style_location_img_container(new_style),
|
||||
location_left_size: !isEmpty(new_style.location_left_icon_size) ? new_style.location_left_icon_size * 2 + 'rpx' : '24rpx',
|
||||
location_right_size: !isEmpty(new_style.location_right_icon_size) ? new_style.location_right_icon_size * 2 + 'rpx' : '24rpx',
|
||||
location_color: !isEmpty(new_style.location_color) ? new_style.location_color : new_style?.position_color || '',
|
||||
location_name_style: this.get_location_name_style(new_content),
|
||||
location_margin: `padding: ${location_margin.margin_top * 2}rpx ${location_margin.margin_right * 2}rpx ${location_margin.margin_bottom * 2}rpx ${location_margin.margin_left * 2}rpx;`, // 悬浮之后有间距,所以要将margin设置成外padding
|
||||
});
|
||||
// this.$emit('onImmersionModelCallBack', this.is_immersion_model);
|
||||
},
|
||||
get_location_name_style(new_content) {
|
||||
const is_search_alone_row = new_content.data_alone_row_value && new_content.data_alone_row_value.includes('search');
|
||||
const is_icon_alone_row = new_content.data_alone_row_value && new_content.data_alone_row_value.includes('icon');
|
||||
let width = 0;
|
||||
if (is_search_alone_row && is_icon_alone_row) {
|
||||
width = 200;
|
||||
} else if (is_search_alone_row || is_icon_alone_row) {
|
||||
width = 100;
|
||||
}
|
||||
if (new_content.theme == '4') {
|
||||
return `${(150 + width) * 2}rpx;`;
|
||||
} else {
|
||||
return `${(100 + width) * 2}rpx;`;
|
||||
}
|
||||
},
|
||||
// 定位设置
|
||||
get_style_location_container(new_style) {
|
||||
const { location_margin = this.old_margin, location_radius = this.old_radius } = new_style;
|
||||
const style = {
|
||||
color_list: new_style?.location_color_list || [],
|
||||
direction: new_style?.location_direction || '',
|
||||
};
|
||||
const height = 32 - location_margin.margin_top - location_margin.margin_bottom;
|
||||
return gradient_computer(style) + radius_computer(location_radius) + `height: ${height * 2}rpx;line-height: ${height * 2}rpx;`;
|
||||
},
|
||||
// 背景图片
|
||||
get_style_location_img_container(new_style) {
|
||||
const { location_background_img = [], location_background_img_style = '2', location_border_show = '0', location_padding = this.old_padding, location_margin = this.old_margin, location_border_size = this.old_padding, location_border_color = '', location_border_style = 'solid' } = new_style;
|
||||
const style = {
|
||||
background_img: location_background_img,
|
||||
background_img_style: location_background_img_style,
|
||||
};
|
||||
let border = ``;
|
||||
if (location_border_show == '1') {
|
||||
border += `border-width: ${location_border_size.padding_top}px ${location_border_size.padding_right}px ${location_border_size.padding_bottom}px ${location_border_size.padding_left}px;border-style: ${location_border_style};border-color: ${location_border_color};`;
|
||||
}
|
||||
const height = 32 - (location_margin.margin_top || 0) - (location_margin.margin_bottom || 0);
|
||||
return background_computer(style) + padding_computer(location_padding) + border + `height: ${(height > 0 ? height : 0) * 2}rpx;line-height: ${(height > 0 ? height : 0) * 2}rpx;box-sizing: border-box;`;
|
||||
},
|
||||
// 获取顶部导航高度
|
||||
get_nav_height() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.article-tabs')
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
this.setData({
|
||||
tabs_top: res.top,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
// 位置回调
|
||||
choice_location_back(e) {
|
||||
this.$emit('onLocationBack', e);
|
||||
},
|
||||
// 打开地址
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
// 返回事件
|
||||
top_nav_left_back_event() {
|
||||
app.globalData.page_back_prev_event();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-container {
|
||||
width: 100%;
|
||||
.header-around {
|
||||
z-index: 12;
|
||||
}
|
||||
.model-top {
|
||||
.roll {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.img {
|
||||
width: 680rpx;
|
||||
}
|
||||
}
|
||||
.model-head {
|
||||
.model-head-content {
|
||||
height: 66rpx;
|
||||
// overflow: hidden;
|
||||
top: -1rpx;
|
||||
/* #ifdef H5 || MP-TOUTIAO */
|
||||
top: 4rpx;
|
||||
/* #endif */
|
||||
}
|
||||
}
|
||||
.model-head-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 66rpx;
|
||||
.function-icon {
|
||||
height: 66rpx;
|
||||
}
|
||||
}
|
||||
.logo-outer-style {
|
||||
height: 56rpx;
|
||||
.logo-style {
|
||||
height: 56rpx;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.indicator-center {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.up_slide_bg {
|
||||
z-index: -1;
|
||||
}
|
||||
.badge-style {
|
||||
top: -20rpx;
|
||||
right: 5rpx;
|
||||
}
|
||||
</style>
|
||||
122
components/diy/hot-zone.vue
Normal file
122
components/diy/hot-zone.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<!-- 热区 -->
|
||||
<view ref="containerRef" class="oh container" :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view ref="hotRef" class="hot pr" :style="style">
|
||||
<image :src="img" class="wh-auto dis-block" mode="widthFix" @load="on_load_img" />
|
||||
<view v-for="(item, index) in hot_data" :key="index" class="hot_box" :style="'left: ' + item.drag_start.x * w_scale1 * w_scale2 + 'px;top:' + item.drag_start.y * h_scale1 * h_scale2 + 'px;width: ' + Math.max(item.drag_end.width * w_scale1 * w_scale2, 1) + 'px;height: ' + Math.max(item.drag_end.height * h_scale1 * h_scale2, 1) + 'px;display: flex;'" :data-value="item.link.page" @tap="url_event"> </view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
img: '',
|
||||
hot_data: [],
|
||||
img_width: 1,
|
||||
img_height: 1,
|
||||
container_ref_h: 0,
|
||||
hot_ref_h: 0,
|
||||
hot_ref_w: 0,
|
||||
w_scale1: 1,
|
||||
h_scale1: 1,
|
||||
w_scale2: 1,
|
||||
h_scale2: 1,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
this.setData({
|
||||
img: new_content.img[0].url,
|
||||
img_width: new_content.hot.img_width || 1,
|
||||
img_height: new_content.hot.img_height || 1,
|
||||
hot_data: new_content.hot.data || [],
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
// 图片加载完成 获取宽高
|
||||
on_load_img(e) {
|
||||
const query = uni.createSelectorQuery();
|
||||
// 选择我们想要的元素
|
||||
query
|
||||
.in(this)
|
||||
.select('.container')
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
// data包含元素的宽度、高度等信息
|
||||
this.setData({
|
||||
container_ref_h: res.height,
|
||||
w_scale1: res.height / this.img_width,
|
||||
h_scale1: res.height / this.img_height,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec(); // 执行查询
|
||||
query
|
||||
.in(this)
|
||||
.select('.hot')
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
// data包含元素的宽度、高度等信息
|
||||
this.setData({
|
||||
w_scale2: res.width / this.container_ref_h,
|
||||
h_scale2: res.height / this.container_ref_h,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec(); // 执行查询
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.hot {
|
||||
min-height: 20rpx;
|
||||
.hot_box {
|
||||
// background: rgba(42, 148, 255, 0.15);
|
||||
// border: 2rpx dashed rgba(142, 198, 255, 0.5);
|
||||
position: absolute;
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
228
components/diy/img-magic.vue
Normal file
228
components/diy/img-magic.vue
Normal file
@@ -0,0 +1,228 @@
|
||||
<template>
|
||||
<!-- 图片魔方 -->
|
||||
<view class="img-magic" :style="style_container + 'height:' + (form.style_actived == 10 ? '100%' : container_size)">
|
||||
<view class="magic-container wh-auto ht-auto" :style="style_img_container">
|
||||
<view class="pr" :style="outer_style">
|
||||
<!-- 风格3 -->
|
||||
<template v-if="form.style_actived == 2">
|
||||
<view class="flex-row align-c jc-c style-size">
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" class="three flex-row" :style="img_spacing" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto ht-auto" :mode="img_fit" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 风格9 -->
|
||||
<template v-else-if="form.style_actived == 8">
|
||||
<view class="flex-row align-c jc-c style-size flex-wrap">
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" :class="['flex-row', { 'style9-top': [0, 1].includes(index), 'style9-bottom': ![0, 1].includes(index) }]" :style="img_spacing" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto ht-auto" :mode="img_fit" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="form.style_actived == 10">
|
||||
<template v-if="form.limit_size == '0'">
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" class="cr-main flex-row" :style="img_spacing + selected_style(item)" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto" mode="widthFix" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" class="cr-main flex-row" :style="img_spacing + selected_style(item) + ';height:' + image_height" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto ht-auto" :mode="img_fit" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" class="cube-selected cr-main flex-row" :style="img_spacing + selected_style(item)" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto ht-auto" :mode="img_fit" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, radius_computer, percentage_count, isEmpty, margin_computer, padding_computer, old_padding, old_margin, border_width } from '@/common/js/common/common.js';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propOuterContainerPadding: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
// 外部样式
|
||||
outer_style: '',
|
||||
// 图片间距设置
|
||||
img_spacing: '',
|
||||
// 图片圆角
|
||||
content_img_radius: '',
|
||||
cube_cell: '',
|
||||
container_size: '',
|
||||
div_width: 0,
|
||||
image_height: '',
|
||||
img_fit: '',
|
||||
content_img_container: '',
|
||||
content_img_style_container: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
// 根据当前页面大小计算成百分比
|
||||
selected_style() {
|
||||
return (item) => {
|
||||
return `overflow: hidden;width: ${this.percentage(this.getSelectedWidth(item))}; height: ${this.percentage(this.getSelectedHeight(item))}; top: ${this.percentage(this.getSelectedTop(item))}; left: ${this.percentage(this.getSelectedLeft(item))};`;
|
||||
};
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
const new_style_spacing = new_content.style_actived === 10 ? 0 : new_style.image_spacing;
|
||||
// 外部样式
|
||||
const outer_spacing = `calc(100% + ${new_style_spacing * 2}rpx)`;
|
||||
const outer_sx = `-${new_style_spacing}rpx`;
|
||||
// 图片间距设置
|
||||
const spacing = `${new_style_spacing}rpx`;
|
||||
// scaleToFill 对应 cover aspectFit 对应 contain center 对应 none
|
||||
let fit = '';
|
||||
if (new_content.img_fit == 'contain') {
|
||||
fit = 'aspectFit';
|
||||
} else if (new_content.img_fit == 'fill') {
|
||||
fit = 'scaleToFill';
|
||||
} else if (new_content.img_fit == 'cover') {
|
||||
fit = 'aspectFill';
|
||||
}
|
||||
const container_height = !isEmpty(new_content.container_height) ? new_content.container_height : sys_width;
|
||||
const density = !isEmpty(new_content.magic_cube_density) ? new_content.magic_cube_density : 4;
|
||||
|
||||
const { margin_left, margin_right } = new_style.common_style;
|
||||
const width = sys_width - margin_left - margin_right - border_width(new_style.common_style) - this.propOuterContainerPadding;
|
||||
const scale = width / 390;
|
||||
this.setData({
|
||||
form: this.propValue.content,
|
||||
new_style: this.propValue.style,
|
||||
outer_style: `width:${outer_spacing};height:${outer_spacing};margin:${outer_sx};`,
|
||||
img_spacing: `padding:${spacing};`,
|
||||
content_img_radius: radius_computer(new_style),
|
||||
style_container: common_styles_computer(new_style.common_style) + 'box-sizing: border-box;',
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex) + 'box-sizing: border-box;',
|
||||
img_fit: fit,
|
||||
div_width: sys_width,
|
||||
container_size: container_height * scale + 'px',
|
||||
cube_cell: sys_width / density,
|
||||
image_height: this.propValue.content.image_height * scale + 'px',
|
||||
content_img_container: common_styles_computer(new_style) + margin_computer(new_style?.margin || old_margin) + 'box-sizing: border-box;',
|
||||
content_img_style_container: common_img_computer(new_style) + padding_computer(new_style?.padding || old_padding) + 'box-sizing: border-box;',
|
||||
});
|
||||
},
|
||||
getSelectedWidth(item) {
|
||||
return (item.end.x - item.start.x + 1) * this.cube_cell;
|
||||
},
|
||||
//计算选中层的高度。
|
||||
getSelectedHeight(item) {
|
||||
return (item.end.y - item.start.y + 1) * this.cube_cell;
|
||||
},
|
||||
//计算选中层的右边距离。
|
||||
getSelectedTop(item) {
|
||||
return (item.start.y - 1) * this.cube_cell;
|
||||
},
|
||||
//计算选中层的左边距离。
|
||||
getSelectedLeft(item) {
|
||||
return (item.start.x - 1) * this.cube_cell;
|
||||
},
|
||||
// 计算成百分比
|
||||
percentage(num) {
|
||||
return percentage_count(num, this.div_width);
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 图片魔方是一个正方形,根据宽度计算高度
|
||||
.img-magic {
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.cube-selected {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.style-size {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
.three {
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.style9-top {
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.style9-bottom {
|
||||
width: calc(100% / 3);
|
||||
height: 50%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
279
components/diy/modules/custom/data-group-rendering.vue
Normal file
279
components/diy/modules/custom/data-group-rendering.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<view :class="'wh-auto pr allSignList-' + propIndex + propKey" :style="'height:' + propDataHeight * propScale + 'px;'">
|
||||
<view v-for="(item, index) in new_list" :key="index" :data-id="item.id" :data-location-x="item.location.x" :data-location-y="item.location.y" :class="'sign-' + propIndex + propKey + ' main-content ' + get_animation_class(item.com_data)" :style="'left:' + get_percentage_count(item.location.x, item.com_data.data_follow, 'left') + ';top:' + get_percentage_count(item.location.y, item.com_data.data_follow, 'top') + ';width:' + get_percentage_count(item.com_data.com_width, item.com_data.data_follow, 'width', item.com_data.is_width_auto, item.com_data.max_width, item.key) + ';height:' + get_percentage_count(item.com_data.com_height, item.com_data.data_follow, 'height', item.com_data.is_height_auto, item.com_data.max_height, item.key) + ';z-index:' + (new_list.length - 1 > 0 ? (new_list.length - 1) - index : 0)">
|
||||
<template v-if="item.key == 'text'">
|
||||
<model-text :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propTitleParams="propShowData.data_name" @url_event="url_event"></model-text>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'img'">
|
||||
<model-image :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propImgParams="propShowData.data_logo" @url_event="url_event"></model-image>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'auxiliary-line'">
|
||||
<model-lines :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId"></model-lines>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'icon'">
|
||||
<model-icon :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-icon>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'panel'">
|
||||
<model-panel :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-panel>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modelText from '@/components/diy/modules/custom/model-text.vue';
|
||||
import modelLines from '@/components/diy/modules/custom/model-lines.vue';
|
||||
import modelImage from '@/components/diy/modules/custom/model-image.vue';
|
||||
import modelIcon from '@/components/diy/modules/custom/model-icon.vue';
|
||||
import modelPanel from '@/components/diy/modules/custom/model-panel.vue';
|
||||
import { location_compute, isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
components: {
|
||||
modelText,
|
||||
modelLines,
|
||||
modelImage,
|
||||
modelIcon,
|
||||
modelPanel,
|
||||
},
|
||||
props: {
|
||||
propCustomList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propSourceList: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
propDataHeight: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataSplitIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propShowData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
data_key: 'id',
|
||||
data_name: 'name'
|
||||
}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
new_list: [],
|
||||
custom_width: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init(this.propCustomList);
|
||||
},
|
||||
propCustomList(val) {
|
||||
this.init(val);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
get_percentage_count() {
|
||||
return (num, data_follow, type, is_auto = '0', max_size = 0, key = '') => {
|
||||
// 检查类型是否为'left'或'top',如果是,则根据跟随数据计算样式
|
||||
if (['left', 'top'].includes(type)) {
|
||||
const { id = '', type: follow_type = 'left' } = data_follow || { id: '', type: 'left' };
|
||||
// 如果id不为空且follow_type与type匹配,则返回原始值的字符串表示
|
||||
if (id !== '' && follow_type === type) {
|
||||
return `${num}px`;
|
||||
}
|
||||
// 如果条件不满足,则根据比例缩放num并返回
|
||||
return `${num * this.propScale}px`;
|
||||
} else {
|
||||
// 如果is_auto设置为'1',则根据type和max_size计算自动样式
|
||||
if (is_auto === '1') {
|
||||
if (type === 'width' || type === 'height') {
|
||||
if (typeof max_size === 'number' && max_size >= 0) {
|
||||
const scaledMaxSize = max_size * this.propScale;
|
||||
const autoStyle = 'auto;';
|
||||
const maxSizeStyle = scaledMaxSize > 0 ? ` max-${type}: ${scaledMaxSize}px;` : '';
|
||||
const whiteSpaceStyle = type === 'width' && scaledMaxSize <= 0 ? ' white-space:nowrap;' : '';
|
||||
return `${ autoStyle }${ maxSizeStyle }${ whiteSpaceStyle }`;
|
||||
} else {
|
||||
return 'auto;';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 微信小程序图片等比缩放对小数点后的内容支持的不是特别的好,需要取向上取整数
|
||||
if (key == 'img' && ['width', 'height'].includes(type)) {
|
||||
// 如果is_auto未设置或条件不满足,则根据比例缩放num并返回
|
||||
return `${ Math.round(num * this.propScale) }px`;
|
||||
} else {
|
||||
// 如果is_auto未设置或条件不满足,则根据比例缩放num并返回
|
||||
return `${num * this.propScale}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
get_animation_class() {
|
||||
return (data) => {
|
||||
const { type = 'none', number = 'infinite' } = data?.animation_style || {};
|
||||
if (type != 'none') {
|
||||
return type + (number == 'infinite' ? `-${number}` : '');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init(this.propCustomList);
|
||||
},
|
||||
methods: {
|
||||
async init(val) {
|
||||
// 如果为空就不进行渲染
|
||||
if (isEmpty(val)) {
|
||||
return;
|
||||
}
|
||||
await this.get_custom_width();
|
||||
this.set_new_list(val);
|
||||
},
|
||||
get_custom_width() {
|
||||
// 获取当前容器的宽度
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('.allSignList-' + this.propIndex + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if (res) {
|
||||
this.setData({
|
||||
custom_width: res.width,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
async set_new_list(val) {
|
||||
// 第一次渲染先渲染全部数据
|
||||
this.setData({
|
||||
new_list: val
|
||||
});
|
||||
// 判断是否有跟随的数据
|
||||
const follow_list = val.filter(item => item.com_data.data_follow && item.com_data?.data_follow?.id !== '');
|
||||
if (follow_list.length > 0) {
|
||||
// 等待页面渲染完成之后再获取内容
|
||||
await this.$nextTick();
|
||||
// 第二次如果有跟随数据,更新对应数据的内容, 如果有超出容器范围的数据,限制其超出容器范围
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.selectAll('.sign-' + this.propIndex + this.propKey)
|
||||
.boundingClientRect((rect) => {
|
||||
if (rect) {
|
||||
// 将返回的内容转成map对象,方便快速查找,节省性能
|
||||
const idMap = new Map(rect.map(item => [item.dataset.id, item]));
|
||||
// 历史数据拷贝,方便后续操作避免每次都更新数据,统一重新渲染
|
||||
const val = JSON.parse(JSON.stringify(this.new_list));
|
||||
val.forEach((item1) => {
|
||||
const { data_follow } = item1.com_data;
|
||||
const targetItem = idMap.get(data_follow?.id);
|
||||
if (targetItem) {
|
||||
const text_item = item1.key == 'text' ? idMap.get((item1?.id || '')+ '') : undefined;
|
||||
if (data_follow?.type === 'left') {
|
||||
// 更新位置信息
|
||||
const location_x = this.updateLocation(targetItem, data_follow, this.propScale, true);
|
||||
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
|
||||
let item_width = item1.com_data.com_width;
|
||||
// 如果是宽度自适应,需要重新判断一下处理逻辑
|
||||
if (item1.com_data?.is_width_auto === '1' && text_item) {
|
||||
item_width = text_item.width;
|
||||
}
|
||||
// 根据容器信息更新位置信息
|
||||
item1.location.x = location_compute(item_width, location_x, this.custom_width);
|
||||
} else if (data_follow?.type === 'top') {
|
||||
// 更新位置信息
|
||||
const location_y = this.updateLocation(targetItem, data_follow, this.propScale, false);
|
||||
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
|
||||
let item_height = item1.com_data.com_height;
|
||||
// 如果是高度自适应,需要重新判断一下处理逻辑
|
||||
if (item1.com_data?.is_height_auto === '1' && text_item) {
|
||||
item_height = text_item.height;
|
||||
}
|
||||
// 根据容器信息更新位置信息
|
||||
item1.location.y = location_compute(item_height, location_y, this.propDataHeight * this.propScale);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
new_list: val
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
}
|
||||
},
|
||||
updateLocation(targetItem, data_follow, scale, isX) {
|
||||
try {
|
||||
const locationValueStr = targetItem.dataset[`location${isX ? 'X' : 'Y'}`];
|
||||
if (locationValueStr == null) {
|
||||
return;
|
||||
}
|
||||
const locationValue = parseFloat(locationValueStr);
|
||||
if (isNaN(locationValue) || scale <= 0 || (isX ? targetItem.width < 0 : targetItem.height < 0)) return;
|
||||
|
||||
return ((locationValue + (data_follow?.spacing || 0)) * scale) + (isX ? targetItem.width : targetItem.height);
|
||||
} catch (error) {
|
||||
console.error(`Error updating location ${isX ? 'X' : 'Y'}:`, error);
|
||||
}
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', e, this.propDataIndex, this.propDataSplitIndex);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main-content {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
290
components/diy/modules/custom/data-rendering.vue
Normal file
290
components/diy/modules/custom/data-rendering.vue
Normal file
@@ -0,0 +1,290 @@
|
||||
<template>
|
||||
<view :class="'wh-auto pr allSignList-' + propIndex + propKey" :style="'height:' + propDataHeight * propScale + 'px;'">
|
||||
<view v-for="(item, index) in new_list" :key="index" :data-id="item.id" :data-location-x="item.location.x" :data-location-y="item.location.y" :class="'sign-' + propIndex + propKey + ' main-content ' + get_animation_class(item.com_data)" :style="'left:' + get_percentage_count(item.location.x, item.com_data.data_follow, 'left') + ';top:' + get_percentage_count(item.location.y, item.com_data.data_follow, 'top') + ';width:' + get_percentage_count(item.com_data.com_width, item.com_data.data_follow, 'width', item.com_data.is_width_auto, item.com_data.max_width, item.key) + ';height:' + get_percentage_count(item.com_data.com_height, item.com_data.data_follow, 'height', item.com_data.is_height_auto, item.com_data.max_height, item.key) + ';z-index:' + (new_list.length - 1 > 0 ? (new_list.length - 1) - index : 0)">
|
||||
<template v-if="item.key == 'text'">
|
||||
<model-text :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propTitleParams="propShowData.data_name" @url_event="url_event"></model-text>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'img'">
|
||||
<model-image :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propImgParams="propShowData.data_logo" @url_event="url_event"></model-image>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'auxiliary-line'">
|
||||
<model-lines :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId"></model-lines>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'icon'">
|
||||
<model-icon :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-icon>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'panel'">
|
||||
<model-panel :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-panel>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'custom-group'">
|
||||
<model-custom-group :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propConfigLoop="propConfigLoop" :propDataWidth="item.com_data.com_width" :propDataHeight="item.com_data.custom_height" :propSourceList="propSourceList" :propGroupSourceList="propGroupSourceList" :propIsCustom="propIsCustom" :propShowData="propShowData"></model-custom-group>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modelText from '@/components/diy/modules/custom/model-text.vue';
|
||||
import modelLines from '@/components/diy/modules/custom/model-lines.vue';
|
||||
import modelImage from '@/components/diy/modules/custom/model-image.vue';
|
||||
import modelIcon from '@/components/diy/modules/custom/model-icon.vue';
|
||||
import modelPanel from '@/components/diy/modules/custom/model-panel.vue';
|
||||
import modelCustomGroup from '@/components/diy/modules/custom/model-custom-group.vue';
|
||||
import { location_compute, isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
components: {
|
||||
modelText,
|
||||
modelLines,
|
||||
modelImage,
|
||||
modelIcon,
|
||||
modelPanel,
|
||||
modelCustomGroup
|
||||
},
|
||||
props: {
|
||||
propCustomList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propSourceList: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
propGroupSourceList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
propDataHeight: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataSplitIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propShowData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
data_key: 'id',
|
||||
data_name: 'name'
|
||||
}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
new_list: [],
|
||||
custom_width: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init(this.propCustomList);
|
||||
},
|
||||
propCustomList(val) {
|
||||
this.init(val);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
get_percentage_count() {
|
||||
return (num, data_follow, type, is_auto = '0', max_size = 0, key = '') => {
|
||||
// 检查类型是否为'left'或'top',如果是,则根据跟随数据计算样式
|
||||
if (['left', 'top'].includes(type)) {
|
||||
const { id = '', type: follow_type = 'left' } = data_follow || { id: '', type: 'left' };
|
||||
// 如果id不为空且follow_type与type匹配,则返回原始值的字符串表示
|
||||
if (id !== '' && follow_type === type) {
|
||||
return `${num}px`;
|
||||
}
|
||||
// 如果条件不满足,则根据比例缩放num并返回
|
||||
return `${num * this.propScale}px`;
|
||||
} else {
|
||||
// 如果is_auto设置为'1',则根据type和max_size计算自动样式
|
||||
if (is_auto === '1') {
|
||||
if (type === 'width' || type === 'height') {
|
||||
if (typeof max_size === 'number' && max_size >= 0) {
|
||||
const scaledMaxSize = max_size * this.propScale;
|
||||
const autoStyle = 'auto;';
|
||||
const maxSizeStyle = scaledMaxSize > 0 ? ` max-${type}: ${scaledMaxSize}px;` : '';
|
||||
const whiteSpaceStyle = type === 'width' && scaledMaxSize <= 0 ? ' white-space:nowrap;' : '';
|
||||
return `${ autoStyle }${ maxSizeStyle }${ whiteSpaceStyle }`;
|
||||
} else {
|
||||
return 'auto;';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 微信小程序图片等比缩放对小数点后的内容支持的不是特别的好,需要取向上取整数
|
||||
if (key == 'img' && ['width', 'height'].includes(type)) {
|
||||
// 如果is_auto未设置或条件不满足,则根据比例缩放num并返回
|
||||
return `${ Math.round(num * this.propScale) }px`;
|
||||
} else {
|
||||
// 如果is_auto未设置或条件不满足,则根据比例缩放num并返回
|
||||
return `${num * this.propScale}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
get_animation_class() {
|
||||
return (data) => {
|
||||
const { type = 'none', number = 'infinite' } = data?.animation_style || {};
|
||||
if (type != 'none') {
|
||||
return type + (number == 'infinite' ? `-${number}` : '');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init(this.propCustomList);
|
||||
},
|
||||
methods: {
|
||||
async init(val) {
|
||||
// 如果为空就不进行渲染
|
||||
if (isEmpty(val)) {
|
||||
return;
|
||||
}
|
||||
await this.get_custom_width();
|
||||
this.set_new_list(val);
|
||||
},
|
||||
get_custom_width() {
|
||||
// 获取当前容器的宽度
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('.allSignList-' + this.propIndex + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if (res) {
|
||||
this.setData({
|
||||
custom_width: res.width,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
async set_new_list(val) {
|
||||
// 第一次渲染先渲染全部数据
|
||||
this.setData({
|
||||
new_list: val
|
||||
});
|
||||
// 判断是否有跟随的数据
|
||||
const follow_list = val.filter(item => item.com_data.data_follow && item.com_data?.data_follow?.id !== '');
|
||||
if (follow_list.length > 0) {
|
||||
await this.$nextTick();
|
||||
// 第二次如果有跟随数据,更新对应数据的内容, 如果有超出容器范围的数据,限制其超出容器范围
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.selectAll('.sign-' + this.propIndex + this.propKey)
|
||||
.boundingClientRect((rect) => {
|
||||
if (rect) {
|
||||
// 将返回的内容转成map对象,方便快速查找,节省性能
|
||||
const idMap = new Map(rect.map(item => [item.dataset.id, item]));
|
||||
// 历史数据拷贝,方便后续操作避免每次都更新数据,统一重新渲染
|
||||
const val = JSON.parse(JSON.stringify(this.new_list));
|
||||
val.forEach((item1) => {
|
||||
const { data_follow } = item1.com_data;
|
||||
const targetItem = idMap.get(data_follow?.id);
|
||||
if (targetItem) {
|
||||
const text_item = item1.key == 'text' ? idMap.get((item1?.id || '')+ '') : undefined;
|
||||
if (data_follow?.type === 'left') {
|
||||
// 更新位置信息
|
||||
const location_x = this.updateLocation(targetItem, data_follow, this.propScale, true);
|
||||
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
|
||||
let item_width = item1.com_data.com_width;
|
||||
// 如果是宽度自适应,需要重新判断一下处理逻辑
|
||||
if (item1.com_data.is_width_auto === '1' && text_item) {
|
||||
item_width = text_item.width;
|
||||
}
|
||||
// 根据容器信息更新位置信息
|
||||
item1.location.x = location_compute(item_width, location_x, this.custom_width);
|
||||
} else if (data_follow?.type === 'top') {
|
||||
// 更新位置信息
|
||||
const location_y = this.updateLocation(targetItem, data_follow, this.propScale, false);
|
||||
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
|
||||
let item_height = item1.com_data.com_height;
|
||||
// 如果是高度自适应,需要重新判断一下处理逻辑
|
||||
if (item1.com_data?.is_height_auto === '1' && text_item) {
|
||||
item_height = text_item.height;
|
||||
}
|
||||
// 根据容器信息更新位置信息
|
||||
item1.location.y = location_compute(item_height, location_y, this.propDataHeight * this.propScale);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
new_list: val
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
}
|
||||
},
|
||||
updateLocation(targetItem, data_follow, scale, isX) {
|
||||
try {
|
||||
const locationValueStr = targetItem.dataset[`location${isX ? 'X' : 'Y'}`];
|
||||
if (locationValueStr == null) {
|
||||
return;
|
||||
}
|
||||
const locationValue = parseFloat(locationValueStr);
|
||||
if (isNaN(locationValue) || scale <= 0 || (isX ? targetItem.width < 0 : targetItem.height < 0)) return;
|
||||
|
||||
const computedValue = ((locationValue + (data_follow?.spacing || 0)) * scale) + (isX ? targetItem.width : targetItem.height);
|
||||
return computedValue;
|
||||
} catch (error) {
|
||||
console.error(`Error updating location ${isX ? 'X' : 'Y'}:`, error);
|
||||
}
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', e, this.propDataIndex, this.propDataSplitIndex);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main-content {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
378
components/diy/modules/custom/model-custom-group.vue
Normal file
378
components/diy/modules/custom/model-custom-group.vue
Normal file
@@ -0,0 +1,378 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="ht-auto" :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view :style="style_content_container">
|
||||
<view class="w h pr" :style="style_content_img_container">
|
||||
<template v-if="data_source_content_list.length > 0 && form.data_source_direction == 'vertical'">
|
||||
<view class="flex-row flex-wrap" :style="'row-gap:' + new_style.row_gap + 'px;column-gap:' + new_style.column_gap + 'px;'">
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" class="ht-auto" :style="gap_width">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1">
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataGroupRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propFieldList="propFieldList" :propDataHeight="propDataHeight" :propScale="custom_scale" :propIsCustom="propIsCustom" :propIsCustomGroup="true" :propShowData="propShowData" :propConfigLoop="propConfigLoop !== '1' ? form.is_use_parent_data : '1'" :propDataIndex="index" :propDataSplitIndex="index1" @url_event="url_event"></dataGroupRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else-if="data_source_content_list.length > 0 && ['vertical-scroll', 'horizontal'].includes(form.data_source_direction)" class="oh ht-auto">
|
||||
<swiper class="w flex" circular="true" :vertical="form.data_source_direction != 'horizontal'" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_view" :style="{ width: '100%', height: swiper_height + 'px' }" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in data_source_content_list" :key="index">
|
||||
<view :class="form.data_source_direction != 'horizontal' ? 'wh-auto ht-auto' : 'flex-row'" :style="form.data_source_direction == 'horizontal' ? 'column-gap:' + new_style.column_gap + 'px;' : ''">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1" class="wh-auto ht-auto" :style="style_chunk_container + swiper_width + (form.data_source_direction == 'horizontal' ? gap_width : 'margin-bottom:' + content_outer_spacing_magin)">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataGroupRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propFieldList="propFieldList" :propDataHeight="propDataHeight" :propScale="custom_scale" :propIsCustom="propIsCustom" :propIsCustomGroup="true" :propShowData="propShowData" :propConfigLoop="propConfigLoop !== '1' ? form.is_use_parent_data : '1'" :propDataIndex="index" :propDataSplitIndex="index1" @url_event="url_event"></dataGroupRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-if="new_style.is_show == '1' && data_source_content_list.length > 1" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
|
||||
<block v-if="new_style.indicator_style == 'num'">
|
||||
<view :style="indicator_style" class="dot-item">
|
||||
<text :style="{ color: new_style.actived_color }">{{ actived_index + 1 }}</text>
|
||||
<text>/{{ data_source_content_list.length }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" :style="indicator_style + (actived_index == index ? 'background:' + new_style.actived_color : '')" class="dot-item" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<template v-else>
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataGroupRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propFieldList="propFieldList" :propDataHeight="propDataHeight" :propScale="custom_scale" :propConfigLoop="propConfigLoop !== '1' ? form.is_use_parent_data : '1'" @url_event="url_event"></dataGroupRendering>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer, percentage_count, isEmpty, get_indicator_style, get_indicator_location_style, border_width, get_is_eligible } from '@/common/js/common/common.js';
|
||||
// a组件调用b组件 b组件调用a组件,为了避免循环引用在uniapp中出问题,复制一个相同的data-group-rendering组件
|
||||
import dataGroupRendering from '@/components/diy/modules/custom/data-group-rendering.vue';
|
||||
const app = getApp();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
dataGroupRendering
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
propDataWidth: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propDataHeight: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propGroupSourceList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
propShowData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
data_key: 'id',
|
||||
data_name: 'name',
|
||||
})
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
custom_scale: 1,
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
custom_list_length: 0,
|
||||
custom_group_field_id: '',
|
||||
source_list: {
|
||||
// 存放手动输入的id
|
||||
data_ids: [],
|
||||
// 手动输入
|
||||
data_list: [],
|
||||
// 自动
|
||||
data_auto_list: [],
|
||||
},
|
||||
data_source_content_list: [],
|
||||
data_source: '',
|
||||
// 内容样式
|
||||
style_content_container: '',
|
||||
style_content_img_container: '',
|
||||
// 数据样式
|
||||
style_chunk_container: '',
|
||||
style_chunk_img_container: '',
|
||||
// 指示器选中的下标
|
||||
actived_index: 0,
|
||||
// 轮播高度
|
||||
swiper_height: 0,
|
||||
swiper_width: 'width: 100%;',
|
||||
// 指示器样式
|
||||
indicator_location_style: '',
|
||||
indicator_style: '',
|
||||
slides_per_view: 1,
|
||||
show_data: { data_key: 'id', data_name: 'name' },
|
||||
old_data_style: {
|
||||
color_list: [{ color: 'rgb(244, 252, 255)', color_percentage: undefined }],
|
||||
direction: '180deg',
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
radius: 0,
|
||||
radius_top_left: 0,
|
||||
radius_top_right: 0,
|
||||
radius_bottom_left: 0,
|
||||
radius_bottom_right: 0,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
},
|
||||
content_outer_spacing_magin: '0rpx',
|
||||
gap_width: '',
|
||||
is_show: true
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
percentage_count,
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
const new_style = this.propValue.data_style;
|
||||
const data_source_id = new_form?.data_source_field?.id || '';
|
||||
// 自定义组的数据源内容切换, 判断是取自定义组数据源内容还是取自定义数据源内容
|
||||
const is_data_source_id = this.propFieldList.filter((item) => item.field == data_source_id);
|
||||
let new_list = [];
|
||||
// 判断是否是循环内容
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 如果自定义组选择了数据源,就按照自定义组的数据源的方式走,否则的话就按照自定义的数据走
|
||||
if (is_data_source_id.length > 0) {
|
||||
const list = this.get_data_source_content_list(this.propSourceList, new_form);
|
||||
// 数据来源的内容
|
||||
new_list = list.length > 0 ? this.get_list(list, new_form, new_style) : [];
|
||||
} else {
|
||||
if (!isEmpty(this.propSourceList)) {
|
||||
const new_source_list = [ this.propSourceList ];
|
||||
new_list = [{ split_list: new_source_list }];
|
||||
} else {
|
||||
new_list = [];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果使用父级数据,就直接使用父级的全部数据,否则的话就没有任何数据
|
||||
if (new_form.is_use_parent_data == '1') {
|
||||
new_list = this.propGroupSourceList;
|
||||
} else {
|
||||
new_list = [];
|
||||
}
|
||||
}
|
||||
// 初始化数据
|
||||
const { common_style, data_content_style, data_style } = new_style;
|
||||
const old_width = this.propDataWidth * this.propScale;
|
||||
// 外层左右间距
|
||||
const outer_spacing = (common_style?.margin_left || 0) + (common_style?.margin_right || 0) + (common_style?.padding_left || 0) + (common_style?.padding_right || 0) + border_width(common_style);
|
||||
// 内容左右间距
|
||||
const content_spacing = (data_content_style?.margin_left || 0) + (data_content_style?.margin_right || 0) + (data_content_style?.padding_left || 0) + (data_content_style?.padding_right || 0) + border_width(data_content_style);
|
||||
// 数据左右间距
|
||||
const internal_spacing = (data_style?.margin_left || 0) + (data_style?.margin_right || 0) + (data_style?.padding_left || 0) + (data_style?.padding_right || 0) + border_width(data_style);
|
||||
// 一行显示的数量
|
||||
const carousel_col = Number(new_form.data_source_carousel_col);
|
||||
// 数据间距
|
||||
const data_spacing = ['vertical', 'horizontal'].includes(new_form.data_source_direction) ? new_style.column_gap * (carousel_col - 1) : 0;
|
||||
// 自定义组件宽度
|
||||
const width = old_width - outer_spacing - content_spacing - internal_spacing - data_spacing;
|
||||
// 自定义组的比例
|
||||
const scale_number = width / this.propDataWidth;
|
||||
const custom_scale = scale_number > 0 ? scale_number : 0;
|
||||
const new_data_style = !isEmpty(new_style.data_style) ? new_style.data_style : this.old_data_style;
|
||||
const new_data_content_style = !isEmpty(new_style.data_content_style)? new_style.data_content_style : this.old_data_style;
|
||||
// 判断是平移还是整屏滚动
|
||||
const { padding_top = 0, padding_bottom = 0, margin_bottom = 0, margin_top = 0 } = new_data_style;
|
||||
let swiper_height = 0;
|
||||
let col = Number(new_form.data_source_carousel_col);
|
||||
// 间距
|
||||
const space_between = new_form.data_source_direction == 'horizontal' ? new_style.column_gap : new_style.row_gap;
|
||||
// 轮播图高度控制
|
||||
if (new_form.data_source_direction == 'horizontal') {
|
||||
swiper_height = this.propDataHeight * custom_scale + padding_top + padding_bottom + margin_bottom + margin_top;
|
||||
} else {
|
||||
// 商品数量大于列数的时候,高度是列数,否则是当前的数量
|
||||
col = new_list.length > carousel_col ? carousel_col : new_list.length;
|
||||
swiper_height = (this.propDataHeight * custom_scale + padding_top + padding_bottom + margin_bottom + margin_top) * col + ((Number(new_form.data_source_carousel_col) - 1) * space_between);
|
||||
}
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.column_gap * (carousel_col - 1)) / carousel_col;
|
||||
// 横向的时候,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
const swiper_width = (new_form.data_source_direction == 'horizontal' && new_style.rolling_fashion != 'translation') ? `width: ${ 100 / carousel_col }%;`: 'width: 100%;';
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
custom_scale: custom_scale,
|
||||
custom_list_length: new_form.custom_list.length - 1,
|
||||
style_container: common_styles_computer(new_style.common_style) + (new_form.is_scroll_bar == '1' ? 'overflow: auto;' : '') + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
style_content_container: common_styles_computer(new_data_content_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_content_img_container: common_img_computer(new_data_content_style),
|
||||
style_chunk_container: common_styles_computer(new_data_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_chunk_img_container: common_img_computer(new_data_style),
|
||||
style_chunk_width: width,
|
||||
data_source_content_list: new_list,
|
||||
data_source: !isEmpty(new_form.data_source)? new_form.data_source : '',
|
||||
indicator_style: get_indicator_style(new_style), // 指示器的样式
|
||||
indicator_location_style: get_indicator_location_style(new_style),
|
||||
swiper_height: swiper_height,
|
||||
swiper_width: swiper_width,
|
||||
content_outer_spacing_magin: space_between + 'px',
|
||||
gap_width: `width: calc(${100 / carousel_col}% - ${gap}px);`,
|
||||
slides_per_view: new_style.rolling_fashion == 'translation' ? (new_form.data_source_direction != 'horizontal' ? col : new_form.data_source_carousel_col ) : 1,
|
||||
is_show: this.get_is_show(new_form),
|
||||
custom_group_field_id: new_form.data_source_field.id,
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, false, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_data_source_content_list(sourceList, form) {
|
||||
if (!isEmpty(sourceList)) {
|
||||
const data_source_id = form?.data_source_field.id || '';
|
||||
let list = this.get_nested_property(sourceList, data_source_id);
|
||||
// 如果是自定义标题,进一步处理嵌套对象中的数据
|
||||
if (sourceList.data) {
|
||||
list = this.get_nested_property(sourceList.data, data_source_id);
|
||||
}
|
||||
return list == '' ? [] : list;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
get_nested_property(obj, path) {
|
||||
// 检查路径参数是否为字符串且非空,若不满足条件则返回空字符串
|
||||
if (typeof path !== 'string' || !path) return [];
|
||||
// 将属性路径字符串拆分为属性键数组
|
||||
const keys = path.split('.');
|
||||
// 使用reduce方法遍历属性键数组,逐层访问对象属性
|
||||
// 如果当前对象存在且拥有下一个属性键,则继续访问;否则返回空字符串
|
||||
return keys.reduce((o, key) => (o != null && o[key] != null ? o[key] : []), obj) ?? [];
|
||||
},
|
||||
get_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation' && form.data_source_direction != 'vertical') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.data_source_carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
this.setData({
|
||||
actived_index: e.detail.current,
|
||||
});
|
||||
},
|
||||
url_event(e, index, split_index) {
|
||||
if (this.data_source == 'goods' && this.data_source_content_list.length > 0) {
|
||||
const list = this.data_source_content_list[index];
|
||||
if (!isEmpty(list) && !isEmpty(list.split_list[split_index])) {
|
||||
const new_list = list.split_list[split_index];
|
||||
if (!isEmpty(new_list)) {
|
||||
// 缓存商品数据
|
||||
app.globalData.goods_data_cache_handle(new_list.data.id, new_list.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
app.globalData.url_open(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
161
components/diy/modules/custom/model-icon.vue
Normal file
161
components/diy/modules/custom/model-icon.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="img-outer pr oh flex-row align-c wh-auto ht-auto" :style="com_style" @tap="url_event">
|
||||
<iconfont :name="'icon-' + icon_class" :color="form.icon_color" :size="form.icon_size * scale + 'px'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { radius_computer, padding_computer, gradient_handle, isEmpty, get_nested_property, get_custom_link, get_is_eligible } from '@/common/js/common/common.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
com_style: '',
|
||||
scale: 1,
|
||||
icon_class: '',
|
||||
icon_url: '',
|
||||
is_show: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
let icon_class_value = '';
|
||||
if (!isEmpty(new_form.icon_class)) {
|
||||
icon_class_value = new_form.icon_class;
|
||||
} else {
|
||||
if (!isEmpty(this.propSourceList)) {
|
||||
let icon = '';
|
||||
// 获取数据源ID
|
||||
const data_source_id = !isEmpty(new_form?.data_source_field?.id || '') && this.propConfigLoop == '1' ? new_form.data_source_field.id : '';
|
||||
// 数据源内容
|
||||
const option = new_form?.data_source_field?.option || {};
|
||||
if (data_source_id.includes(';')) {
|
||||
const ids = data_source_id.split(';');
|
||||
let url = '';
|
||||
ids.forEach((item, index) => {
|
||||
url += this.data_handling(item) + (index != ids.length - 1 ? (option?.join || '') : '');
|
||||
});
|
||||
icon = url;
|
||||
} else {
|
||||
// 不输入商品, 文章和品牌时,从外层处理数据
|
||||
icon = this.data_handling(data_source_id);
|
||||
}
|
||||
icon_class_value = (option?.first || '') + icon + (option?.last || '');
|
||||
} else {
|
||||
icon_class_value = '';
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
form: new_form,
|
||||
scale: this.propScale,
|
||||
com_style: this.get_com_style(new_form, this.propScale),
|
||||
icon_class: icon_class_value,
|
||||
icon_url: this.get_icon_link(new_form),
|
||||
is_show: this.get_is_show(new_form),
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_icon_link(new_form) {
|
||||
let url = '';
|
||||
if (!isEmpty(new_form.icon_link)) {
|
||||
url = new_form.icon_link?.page || '';
|
||||
} else {
|
||||
// 获取数据源ID
|
||||
const data_source_link_id = !isEmpty(new_form?.data_source_link_field?.id || '') && this.propConfigLoop == '1' ? new_form?.data_source_link_field?.id : '';
|
||||
// 数据源内容
|
||||
const source_link_option = new_form?.data_source_link_field?.option || {};
|
||||
url = get_custom_link(data_source_link_id, this.propSourceList, source_link_option)
|
||||
}
|
||||
return url;
|
||||
},
|
||||
data_handling(data_source_id) {
|
||||
// 不输入商品, 文章和品牌时,从外层处理数据
|
||||
let icon = get_nested_property(this.propSourceList, data_source_id);
|
||||
// 如果是商品,品牌,文章的图片, 其他的切换为从data中取数据
|
||||
if (this.propIsCustom && !isEmpty(this.propSourceList.data)) {
|
||||
icon = get_nested_property(this.propSourceList.data, data_source_id);
|
||||
}
|
||||
return icon;
|
||||
},
|
||||
get_com_style(form, scale) {
|
||||
let style = `${ gradient_handle(form.color_list, form.direction) } ${ radius_computer(form.bg_radius, scale, true) };transform: rotate(${form.icon_rotate}deg);${ padding_computer(form.icon_padding, scale, true) };`;
|
||||
if (form.border_show == '1') {
|
||||
style += `border: ${form.border_size * scale }px ${form.border_style} ${form.border_color};box-sizing: border-box;`;
|
||||
}
|
||||
if (form.icon_location == 'center') {
|
||||
style += `justify-content: center;`;
|
||||
} else if (form.icon_location == 'left') {
|
||||
style += `justify-content: flex-start;`;
|
||||
} else if (form.icon_location == 'right') {
|
||||
style += `justify-content: flex-end;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', this.icon_url);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
178
components/diy/modules/custom/model-image.vue
Normal file
178
components/diy/modules/custom/model-image.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="img-outer pr wh-auto ht-auto" :style="border_style" @tap="url_event">
|
||||
<imageEmpty :propImageSrc="img" :propStyle="image_style" propErrorStyle="width: 60rpx;height: 60rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { percentage_count, radius_computer, isEmpty, get_nested_property, get_custom_link, get_is_eligible } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propImgParams: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
img: '',
|
||||
img_url: '',
|
||||
image_style: '',
|
||||
border_style: '',
|
||||
keyMap: {
|
||||
goods: 'images',
|
||||
article: 'cover',
|
||||
brand: 'logo'
|
||||
},
|
||||
is_show: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
img: this.get_img_url(new_form),
|
||||
image_style: this.get_image_style(new_form, this.propScale),
|
||||
border_style: this.get_border_style(new_form, this.propScale),
|
||||
img_url: this.get_img_link(new_form),
|
||||
is_show: this.get_is_show(new_form),
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_img_link(form) {
|
||||
let url = '';
|
||||
if (!isEmpty(form.link)) {
|
||||
url = form.link?.page || '';
|
||||
} else {
|
||||
// 获取数据源ID
|
||||
const data_source_link_id = !isEmpty(form?.data_source_link_field?.id || '') && this.propConfigLoop == '1' ? form.data_source_link_field.id : '';
|
||||
// 数据源内容
|
||||
const source_link_option = form?.data_source_link_field?.option || {};
|
||||
url = get_custom_link(data_source_link_id, this.propSourceList, source_link_option)
|
||||
}
|
||||
return url;
|
||||
},
|
||||
get_img_url(form) {
|
||||
if (!isEmpty(form.img[0])) {
|
||||
return form.img[0];
|
||||
} else {
|
||||
if (!isEmpty(this.propSourceList)) {
|
||||
let image_url = '';
|
||||
// 获取数据源ID
|
||||
const data_source_id = !isEmpty(form?.data_source_field?.id || '') && this.propConfigLoop == '1' ? form.data_source_field.id : '';
|
||||
// 数据源内容
|
||||
const option = form?.data_source_field?.option || {};
|
||||
if (data_source_id.includes(';')) {
|
||||
const ids = data_source_id.split(';');
|
||||
let url = '';
|
||||
ids.forEach((item, index) => {
|
||||
url += this.data_handling(item) + (index != ids.length - 1 ? (option?.join || '') : '');
|
||||
});
|
||||
image_url = url;
|
||||
} else {
|
||||
image_url = this.data_handling(data_source_id);
|
||||
}
|
||||
return (option?.first || '') + image_url + (option?.last || '');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
data_handling(data_source_id) {
|
||||
// 不输入商品, 文章和品牌时,从外层处理数据
|
||||
let image_url = get_nested_property(this.propSourceList, data_source_id);
|
||||
// 如果是商品,品牌,文章的图片, 其他的切换为从data中取数据
|
||||
if (this.propIsCustom && !isEmpty(this.propSourceList.data)) {
|
||||
// 判断是否是同一标志
|
||||
if (data_source_id == this.propImgParams) {
|
||||
// 如果是符合条件的标志,先判断新的图片是否存在,存在就取新的图片,否则的话取原来的图片
|
||||
image_url = !isEmpty(this.propSourceList.new_cover)? this.propSourceList.new_cover[0]?.url || '' : get_nested_property(this.propSourceList.data, data_source_id);
|
||||
} else {
|
||||
image_url = get_nested_property(this.propSourceList.data, data_source_id);
|
||||
}
|
||||
}
|
||||
return image_url;
|
||||
},
|
||||
get_image_style(form, scale) {
|
||||
return `width: ${percentage_count(form.img_width, form.com_width)}; height: ${percentage_count(form.img_height, form.com_height)};transform: rotate(${form.img_rotate}deg); ${radius_computer(form.img_radius, scale, true)};`;
|
||||
},
|
||||
get_border_style(form, scale) {
|
||||
let style = ``;
|
||||
if (form.border_show == '1') {
|
||||
style += `border: ${form.border_size * scale }px ${form.border_style} ${form.border_color}; ${radius_computer(form.border_radius, scale, true)};box-sizing: border-box;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', this.img_url);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.img-outer {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
94
components/diy/modules/custom/model-lines.vue
Normal file
94
components/diy/modules/custom/model-lines.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<view v-if="is_show" :style="border_style"></view>
|
||||
</template>
|
||||
<script>
|
||||
import { get_is_eligible } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
border_style: '',
|
||||
is_show: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
border_style: this.get_border_style(new_form, this.propScale),
|
||||
is_show: this.get_is_show(new_form),
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_border_style(form, scale) {
|
||||
if (form.line_settings === 'horizontal') {
|
||||
return `margin: 10rpx 0;border-bottom: ${form.line_size * scale }px ${form.line_style} ${form.line_color};`;
|
||||
} else {
|
||||
return `margin: 0 10rpx;height:100%;border-right: ${form.line_size * scale }px ${form.line_style} ${form.line_color};`;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
133
components/diy/modules/custom/model-panel.vue
Normal file
133
components/diy/modules/custom/model-panel.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="wh-auto ht-auto re oh" :style="com_style" @tap="url_event">
|
||||
<view class="wh-auto ht-auto" :style="com_img_style"></view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { radius_computer, background_computer, gradient_handle, isEmpty, get_custom_link, get_is_eligible } from '@/common/js/common/common.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
text_title: '',
|
||||
text_style: '',
|
||||
com_style: '',
|
||||
panel_url: '',
|
||||
is_show: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
let url = '';
|
||||
if (!isEmpty(new_form.link)) {
|
||||
url = new_form.link?.page || '';
|
||||
} else {
|
||||
// 获取数据源ID
|
||||
const data_source_link_id = !isEmpty(new_form?.data_source_link_field?.id || '') && this.propConfigLoop == '1' ? new_form.data_source_link_field.id : '';
|
||||
// 数据源内容
|
||||
const source_link_option = new_form?.data_source_link_field?.option || {};
|
||||
url = get_custom_link(data_source_link_id, this.propSourceList, source_link_option);
|
||||
}
|
||||
this.setData({
|
||||
form: new_form,
|
||||
com_style: this.get_com_style(new_form, this.propScale),
|
||||
com_img_style: this.get_com_img_style(new_form),
|
||||
panel_url: url,
|
||||
is_show: this.get_is_show(new_form),
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_com_style(form, scale) {
|
||||
let style = `${ gradient_handle(form.color_list, form.direction) } ${radius_computer(form.bg_radius, scale, true)}; transform: rotate(${form.panel_rotate}deg);`;
|
||||
if (form.border_show == '1') {
|
||||
style += `border: ${form.border_size * scale }px ${form.border_style} ${form.border_color};box-sizing: border-box;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
get_com_img_style(form) {
|
||||
const data = {
|
||||
background_img: form?.background_img || [],
|
||||
background_img_style: form?.background_img_style || '2'
|
||||
}
|
||||
return background_computer(data);
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', this.panel_url);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.break {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
.rich-text-content {
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
* {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
236
components/diy/modules/custom/model-text.vue
Normal file
236
components/diy/modules/custom/model-text.vue
Normal file
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="img-outer wh-auto ht-auto re oh" :style="com_style" @tap="url_event">
|
||||
<view :style="text_style" :class="'break ' + text_line_class">
|
||||
<template v-if="form.is_rich_text == '1'">
|
||||
<mp-html :content="text_title" />
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ text_title }}
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { radius_computer, padding_computer, isEmpty, gradient_handle, get_nested_property, get_custom_link, get_is_eligible, custom_condition_data } from '@/common/js/common/common.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propTitleParams: {
|
||||
type: String,
|
||||
default: 'name'
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
text_title: '',
|
||||
text_style: '',
|
||||
com_style: '',
|
||||
text_url: '',
|
||||
keyMap: {
|
||||
goods: 'title',
|
||||
article: 'title',
|
||||
brand: 'name'
|
||||
},
|
||||
is_show: true,
|
||||
text_line_class: ''
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
let url = '';
|
||||
if (!isEmpty(new_form.text_link)) {
|
||||
url = new_form.text_link?.page || '';
|
||||
} else {
|
||||
// 获取数据源ID
|
||||
const data_source_link_id = !isEmpty(new_form?.data_source_link_field?.id || '') && this.propConfigLoop == '1' ? new_form.data_source_link_field.id : '';
|
||||
// 数据源内容
|
||||
const source_link_option = new_form?.data_source_link_field?.option || {};
|
||||
// 调用方法处理数据显示
|
||||
url = get_custom_link(data_source_link_id, this.propSourceList, source_link_option);
|
||||
}
|
||||
this.setData({
|
||||
form: new_form,
|
||||
text_title: (new_form?.text_captions || '') + this.get_text_title(new_form),
|
||||
text_style: this.get_text_style(new_form, this.propScale),
|
||||
com_style: this.get_com_style(new_form, this.propScale),
|
||||
text_url: url,
|
||||
is_show: this.get_is_show(new_form),
|
||||
text_line_class: new_form.width_omit_num == '0' || new_form.is_rich_text == '1' ? '' : `text-line-${ new_form?.width_omit_num || '' }`
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_text_title(form) {
|
||||
let text = '';
|
||||
if (!isEmpty(form.text_title)) {
|
||||
// 存储待处理的文本标题
|
||||
let new_title = JSON.parse(JSON.stringify((form.text_title)));
|
||||
let new_field_list = this.propFieldList;
|
||||
// 判断是否是自定义组
|
||||
if (this.propIsCustomGroup && !isEmpty(this.propCustomGroupFieldId)) {
|
||||
// 取出对应自定义组的内容
|
||||
const group_option_list = new_field_list.find((item) => item.field === this.propCustomGroupFieldId);
|
||||
// 取出自定义组内部数据源参数的详细数据
|
||||
new_field_list = group_option_list?.data || [];
|
||||
}
|
||||
// 遍历字段列表,替换文本标题中的占位符
|
||||
if (!isEmpty(new_field_list)) {
|
||||
new_field_list.forEach((item) => {
|
||||
const new_field = '${' + item.field + '}';
|
||||
if (form.text_title.includes(new_field)) {
|
||||
// 获取到字段的真实数据
|
||||
const field_value = custom_condition_data(item.field, item, this.propSourceList, this.propIsCustom);
|
||||
// 使用正则表达式替换文本标题
|
||||
const regular = new RegExp(`\\$\\{\\s*${item.field}\\s*\\}`, 'g');
|
||||
// 替换后的内容赋值给原内容, 确保后续可以继续替换
|
||||
new_title = new_title.replace(regular, field_value);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 将内容替换为处理后的标题
|
||||
text = new_title;
|
||||
} else {
|
||||
let text_title = '';
|
||||
// 获取数据源ID
|
||||
const data_source_id = !isEmpty(form?.data_source_field?.id || []) && this.propConfigLoop == '1' ? form?.data_source_field?.id : [];
|
||||
// 数据源内容
|
||||
const option = form?.data_source_field?.option || [];
|
||||
// 多选判断
|
||||
if (data_source_id.length > 0) {
|
||||
text_title += form?.data_split?.left || '';
|
||||
// 遍历取出所有的值
|
||||
data_source_id.forEach((source_id, index) => {
|
||||
const sourceList = option.find((item) => item.field == source_id);
|
||||
// 根据数据源ID是否包含点号来区分处理方式
|
||||
if (source_id.includes(';')) {
|
||||
const ids = source_id.split(';');
|
||||
let source_text = '';
|
||||
ids.forEach((item, index) => {
|
||||
source_text += this.data_handling(item) + (index != ids.length - 1 ? (sourceList?.join || '') : '');
|
||||
});
|
||||
text_title += (sourceList?.first || '') + source_text + (sourceList?.last || '');
|
||||
} else {
|
||||
text_title += (sourceList?.first || '') + this.data_handling(source_id) + (sourceList?.last || '');
|
||||
}
|
||||
if (index < data_source_id.length - 1) {
|
||||
text_title += form?.data_split?.middle || '';
|
||||
}
|
||||
});
|
||||
text_title += form?.data_split?.right || '';
|
||||
}
|
||||
// 如果是商品的标题或者是品牌的名称,需要判断是否有新的标题,没有的话就取原来的标题
|
||||
text = text_title;
|
||||
}
|
||||
return text;
|
||||
},
|
||||
data_handling(data_source_id) {
|
||||
let text = get_nested_property(this.propSourceList, data_source_id);
|
||||
// 如果是商品的标题或者是品牌的名称,需要判断是否有新的标题,没有的话就取原来的标题
|
||||
if (this.propIsCustom && !isEmpty(this.propSourceList.data)) {
|
||||
// 其他的切换为从data中取数据
|
||||
if (data_source_id == this.propTitleParams) {
|
||||
// 如果是符合条件的标志,先判断新的标题是否存在,存在就取新的标题,否则的话取原来的标题
|
||||
text = !isEmpty(this.propSourceList.new_title) ? this.propSourceList.new_title : get_nested_property(this.propSourceList.data, data_source_id);
|
||||
} else {
|
||||
text = get_nested_property(this.propSourceList.data, data_source_id);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
},
|
||||
get_text_style(form, scale) {
|
||||
let style = `font-size: ${form.text_size * scale }px;line-height: ${ (typeof form.line_text_size === "number" ? form.line_text_size : form.text_size) * scale }px;color: ${form.text_color}; text-align: ${form.text_location}; transform: rotate(${form.text_rotate}deg);text-decoration: ${form.text_option};${padding_computer(form.text_padding, scale, true)};box-sizing: border-box;`;
|
||||
if (form.text_weight == 'italic') {
|
||||
style += `font-style: italic`;
|
||||
} else if (['bold', '500'].includes(form.text_weight)) {
|
||||
style += `font-weight: bold;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
get_com_style(form, scale) {
|
||||
let style = `${ gradient_handle(form.color_list, form.direction) } ${radius_computer(form.bg_radius, scale, true)}`;
|
||||
if (form.border_show == '1') {
|
||||
style += `border: ${form.border_size * scale }px ${form.border_style} ${form.border_color};box-sizing: border-box;`;
|
||||
}
|
||||
// 是富文本并且开启了上下滚动的开关
|
||||
if (form.is_rich_text == '1' && form.is_up_down == '1') {
|
||||
style += `overflow-y: auto;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', this.text_url)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.break {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
.rich-text-content {
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
* {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
304
components/diy/modules/data-magic/custom/index.vue
Normal file
304
components/diy/modules/data-magic/custom/index.vue
Normal file
@@ -0,0 +1,304 @@
|
||||
<template>
|
||||
<view :style="style_content_container">
|
||||
<view :style="style_content_img_container">
|
||||
<template v-if="!isEmpty(form.data_source) && form.data_source_is_loop !== '0'">
|
||||
<view v-if="data_source_content_list.length > 0 && form.data_source_direction == 'vertical'">
|
||||
<view class="flex-row flex-wrap" :style="'row-gap:' + new_style.row_gap + 'px;column-gap:' + new_style.column_gap + 'px;'">
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" class="ht-auto" :style="gap_width">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1">
|
||||
<view :style="style_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propSourceType="form.data_source" :propDataHeight="form.height" :propScale="scale" :propDataIndex="index" :propDataSplitIndex="index1" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="data_source_content_list.length > 0 && ['vertical-scroll', 'horizontal'].includes(form.data_source_direction)" class="oh pr">
|
||||
<swiper class="w flex" circular="true" :vertical="form.data_source_direction != 'horizontal'" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_view" :style="{ width: '100%', height: swiper_height + 'px' }" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in data_source_content_list" :key="index">
|
||||
<view :class="form.data_source_direction != 'horizontal' ? '' : 'flex-row'" :style="form.data_source_direction == 'horizontal' ? 'column-gap:' + new_style.column_gap + 'px;' : ''">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1" :style="style_container + swiper_width + (form.data_source_direction == 'horizontal' ? gap_width : 'margin-bottom:' + content_outer_spacing_magin)">
|
||||
<view class="wh-auto ht-auto oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propSourceType="form.data_source" :propDataHeight="form.height" :propScale="scale" :propDataIndex="index" :propDataSplitIndex="index1" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view :style="style_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propConfigLoop="form.data_source_is_loop || '1'" :propDataHeight="form.height" :propScale="scale" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else-if="!isEmpty(form.data_source) && form.data_source_is_loop == '0'">
|
||||
<view :style="style_container">
|
||||
<view class="w h oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propSourceList="{}" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propSourceType="form.data_source" :propDataHeight="form.height" :propScale="scale" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view :style="style_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propConfigLoop="form.data_source_is_loop || '1'" :propDataHeight="form.height" :propScale="scale" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { padding_computer, isEmpty, margin_computer, gradient_computer, radius_computer, background_computer, common_styles_computer, common_img_computer, border_width, box_shadow_computer, border_computer, old_border_and_box_shadow, old_margin, old_padding, old_radius } from '@/common/js/common/common.js';
|
||||
import dataRendering from '@/components/diy/modules/custom/data-rendering.vue';
|
||||
const app = getApp();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
dataRendering
|
||||
},
|
||||
props: {
|
||||
propKey: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propMagicScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataSpacing: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propDataIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
scale: 1,
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
div_width: 0,
|
||||
div_height: 0,
|
||||
custom_list_length: 0,
|
||||
data_source_content_list: [],
|
||||
data_source: '',
|
||||
// 一屏显示的数量
|
||||
slides_per_view: 1,
|
||||
// 轮播高度
|
||||
swiper_height: 0,
|
||||
swiper_width: 'width: 100%;',
|
||||
show_data: { data_key: 'id', data_name: 'name' },
|
||||
gap_width: '',
|
||||
content_outer_spacing_magin: '0rpx',
|
||||
defalt_style: {
|
||||
color_list: [{ color: '', color_percentage: undefined }],
|
||||
direction: '180deg',
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
radius: 0,
|
||||
radius_top_left: 0,
|
||||
radius_top_right: 0,
|
||||
radius_bottom_left: 0,
|
||||
radius_bottom_right: 0,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
},
|
||||
style_content_container: '',
|
||||
style_content_img_container: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
get_percentage_count() {
|
||||
return (num) => {
|
||||
return num * this.scale + 'px';
|
||||
};
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
if (!isEmpty(this.propValue)) {
|
||||
const new_form = this.propValue.data_content;
|
||||
const new_style = this.propValue.data_style;
|
||||
const { data_common_style = {}, data_color_list = [], data_direction = '180deg', data_radius = old_radius, data_background_img = [], data_background_img_style = '2', data_chunk_padding = old_padding, data_chunk_margin = old_margin, data_content_style = {}, data_pattern = old_border_and_box_shadow } = new_style;
|
||||
const style_data = {
|
||||
color_list: data_color_list,
|
||||
direction: data_direction,
|
||||
}
|
||||
const style_img_data = {
|
||||
background_img: data_background_img,
|
||||
background_img_style: data_background_img_style,
|
||||
}
|
||||
// 数据来源的内容
|
||||
let list = [];
|
||||
if (new_form.is_custom_data == '1') {
|
||||
if (Number(new_form.data_source_content.data_type) === 0) {
|
||||
list = new_form.data_source_content.data_list;
|
||||
} else {
|
||||
list = new_form.data_source_content.data_auto_list.map(item => ({
|
||||
id: Math.random(),
|
||||
new_cover: [],
|
||||
new_title: '',
|
||||
data: item,
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
list = new_form.data_source_content.data_list;
|
||||
}
|
||||
const new_list = list.length > 0 ? this.get_list(list, new_form, new_style) : [];
|
||||
// 计算宽度
|
||||
const { padding_left, padding_right, padding_top, padding_bottom } = data_chunk_padding;
|
||||
const { margin_left, margin_right, margin_bottom, margin_top } = data_chunk_margin;
|
||||
const old_width = new_form.width * this.propMagicScale;
|
||||
// 数据宽度
|
||||
const data_style = padding_left + padding_right + margin_left + margin_right + border_width(data_pattern);
|
||||
// 通用样式
|
||||
const chunk_padding = new_style?.chunk_padding || old_padding;
|
||||
const chunk_margin = new_style?.chunk_margin || old_margin;
|
||||
const common_styles = (chunk_margin?.margin_left || 0) + (chunk_margin?.margin_right || 0) + (chunk_padding?.padding_left || 0) + (chunk_padding?.padding_right || 0) + border_width(data_common_style);
|
||||
// 内容左右间距
|
||||
const content_spacing = (data_content_style?.margin_left || 0) + (data_content_style?.margin_right || 0) + (data_content_style?.padding_left || 0) + (data_content_style?.padding_right || 0) + border_width(data_content_style);
|
||||
const carousel_col = Number(new_form.data_source_carousel_col);
|
||||
// 数据间距
|
||||
const data_spacing = ['vertical', 'horizontal'].includes(new_form.data_source_direction) ? new_style.column_gap * (carousel_col - 1) : 0;
|
||||
// 当前容器的宽度 减去 左右两边的padding值 再减去 数据间距的一半 再除以 容器的宽度 得到比例 再乘以数据魔方的比例
|
||||
const width = old_width - data_style - content_spacing - common_styles - data_spacing - (this.propDataSpacing / 2);
|
||||
// 计算缩放比例
|
||||
// 比例增加最小值判断
|
||||
const scale_number = width / new_form.width;
|
||||
const new_scale = scale_number > 0 ? scale_number : 0;
|
||||
// 间距
|
||||
const space_between = new_form.data_source_direction == 'horizontal' ? new_style.column_gap : new_style.row_gap;
|
||||
// 判断是平移还是整屏滚动
|
||||
let swiper_height = 0;
|
||||
// 商品数量大于列数的时候,高度是列数,否则是当前的数量
|
||||
const col = new_list.length > carousel_col ? carousel_col : new_list.length;
|
||||
// 轮播图高度控制
|
||||
if (new_form.data_source_direction == 'horizontal') {
|
||||
swiper_height = new_form.height * new_scale + padding_top + padding_bottom + margin_bottom + margin_top;
|
||||
} else {
|
||||
swiper_height = (new_form.height * new_scale + padding_top + padding_bottom + margin_bottom + margin_top) * col + ((carousel_col - 1) * space_between);
|
||||
}
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.column_gap * (carousel_col - 1)) / carousel_col;
|
||||
// 横向的时候,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
const swiper_width = (new_form.data_source_direction == 'horizontal' && new_style.rolling_fashion != 'translation') ? `width: ${ 100 / carousel_col }%;`: 'width: 100%;';
|
||||
const content_style = !isEmpty(new_style.data_content_style)? new_style.data_content_style : this.defalt_style;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
div_width: width,
|
||||
scale: new_scale,
|
||||
custom_list_length: new_form.custom_list.length - 1,
|
||||
style_content_container: common_styles_computer(content_style),
|
||||
style_content_img_container: common_img_computer(content_style),
|
||||
style_container: gradient_computer(style_data) + radius_computer(data_radius) + margin_computer(data_chunk_margin) + box_shadow_computer(data_pattern) + border_computer(data_pattern), // 用于样式显示
|
||||
style_img_container: padding_computer(data_chunk_padding) + background_computer(style_img_data) + 'box-sizing: border-box;',
|
||||
data_source_content_list: new_list,
|
||||
data_source: !isEmpty(new_form.data_source)? new_form.data_source : '',
|
||||
slides_per_view: new_style.rolling_fashion == 'translation' ? (new_form.data_source_direction != 'horizontal' ? col : carousel_col) : 1,
|
||||
swiper_height: swiper_height,
|
||||
swiper_width: swiper_width,
|
||||
show_data: new_form?.show_data || { data_key: 'id', data_name: 'name' },
|
||||
content_outer_spacing_magin: space_between + 'px',
|
||||
gap_width: `width: calc(${100 / carousel_col}% - ${gap}px);`,
|
||||
});
|
||||
}
|
||||
},
|
||||
get_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation' && form.data_source_direction != 'vertical') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.data_source_carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
this.$emit('onCarouselChange', e.detail.current, this.propDataIndex);
|
||||
},
|
||||
url_event(e, index, split_index) {
|
||||
if (this.form.data_source == 'goods' && this.data_source_content_list.length > 0) {
|
||||
const list = this.data_source_content_list[index];
|
||||
if (!isEmpty(list) && !isEmpty(list.split_list[split_index])) {
|
||||
const new_list = list.split_list[split_index];
|
||||
if (!isEmpty(new_list)) {
|
||||
// 缓存商品数据
|
||||
app.globalData.goods_data_cache_handle(new_list.data.id, new_list.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
app.globalData.url_open(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.main-content {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
142
components/diy/modules/data-magic/magic-carousel.vue
Normal file
142
components/diy/modules/data-magic/magic-carousel.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<view class="wh-auto ht-auto oh" :style="style_container">
|
||||
<view class="pr oh wh-auto ht-auto" :style="style_img_container">
|
||||
<swiper circular="true" :autoplay="propValue.data_style.is_roll == '1'" :interval="propValue.data_style.interval_time * 1000" :duration="500" :vertical="propValue.data_style.rotation_direction == 'vertical'" :next-margin="next_margin" :display-multiple-items="slides_per_view" class="swiper" style="height: 100%" @change="carousel_change">
|
||||
<swiper-item v-for="(item1, index1) in propValue.data_content.list" :key="index1">
|
||||
<template v-if="propType === 'img'">
|
||||
<view class="wh-auto ht-auto" :data-value="item1.carousel_link.page" @tap="url_event">
|
||||
<imageEmpty :propImageSrc="item1.carousel_img[0]" :propStyle="propValue.data_style.get_img_radius" :propImgFit="propValue.data_content.fit" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="wh-auto ht-auto" :style="shop_spacing">
|
||||
<product-list-show :propKey="propKey" :propOuterflex="propValue.data_content.goods_outerflex" :propFlex="propValue.data_content.goods_flex" :propNum="show_num" :propActived="propActived" :propIsShow="propValue.data_content.is_show" :propChunkPadding="propValue.data_style.chunk_padding" :propValue="item1.split_list" :propGoodStyle="propGoodStyle" :propContentImgRadius="propValue.data_style.get_img_radius" @url_event="url_event"></product-list-show>
|
||||
</view>
|
||||
</template>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { gradient_computer, radius_computer, padding_computer, background_computer, isEmpty, border_computer, box_shadow_computer, old_border_and_box_shadow, old_margin, old_radius, old_padding, margin_computer } from "@/common/js/common/common.js";
|
||||
const app = getApp();
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import productListShow from '@/components/diy/modules/data-magic/product-list-show.vue';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
productListShow,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propContentImgRadius: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propType: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propActived: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
propGoodStyle: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
propDataIndex: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
slides_per_view: 1,
|
||||
show_num: 1,
|
||||
shop_spacing: '',
|
||||
next_margin: '0rpx',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
if (!isEmpty(this.propValue)) {
|
||||
const { data_color_list = [], data_direction = '180deg', data_chunk_margin = old_margin, data_radius = old_radius, data_pattern = old_border_and_box_shadow, data_background_img = [], data_background_img_style = '2', data_chunk_padding = old_padding } = this.propValue.data_style;
|
||||
const style_data = {
|
||||
color_list: data_color_list,
|
||||
direction: data_direction,
|
||||
}
|
||||
const style_img_data = {
|
||||
background_img: data_background_img,
|
||||
background_img_style: data_background_img_style,
|
||||
}
|
||||
let slides_per_view = 1;
|
||||
let show_num = 1;
|
||||
// 商品时的处理逻辑
|
||||
const { goods_outerflex, goods_num } = this.propValue.data_content;
|
||||
const { rotation_direction, rolling_fashion, data_goods_gap } = this.propValue.data_style;
|
||||
// 图片时的处理
|
||||
if (this.propType === 'img') {
|
||||
slides_per_view = 1; // 能够同时显示的slides数量
|
||||
} else {
|
||||
// 判断是平移还是整屏滚动, 平移的时候是一个为1组,如果是整屏滚动,就为一屏为一组
|
||||
if (rolling_fashion == 'translation') {
|
||||
// 如果是商品是横排的,轮播也是横排的,就不对商品进行拆分/如果商品是竖排的,轮播也是竖排的,不对商品进行拆分
|
||||
if ((goods_outerflex == 'row' && rotation_direction == 'horizontal') || (goods_outerflex == 'col' && rotation_direction == 'vertical')) {
|
||||
slides_per_view = goods_num; // 能够同时显示的slides数量
|
||||
show_num = 1; // 一屏显示的数量 用于商品内部处理显示
|
||||
} else {
|
||||
slides_per_view = 1; // 能够同时显示的slides数量
|
||||
show_num = goods_num; // 一屏显示的数量 用于商品内部处理显示
|
||||
}
|
||||
} else {
|
||||
// 切屏的时候为多个为一组
|
||||
show_num = goods_num; // 一屏显示的数量 用于商品内部处理显示
|
||||
slides_per_view = 1; // 能够同时显示的slides数量
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
style_container: gradient_computer(style_data) + radius_computer(data_radius) + margin_computer(data_chunk_margin) + box_shadow_computer(data_pattern) + border_computer(data_pattern), // 用于样式显示
|
||||
style_img_container: padding_computer(data_chunk_padding) + background_computer(style_img_data) + 'box-sizing: border-box;',
|
||||
next_margin: rolling_fashion == 'translation' && rotation_direction == 'horizontal' ? `-${ data_goods_gap * 2 }rpx` : '0rpx',
|
||||
shop_spacing: this.propType === 'img' ? 'margin-right: 0px;' : `margin-right: ${ data_goods_gap * 2 }rpx;`,
|
||||
slides_per_view: slides_per_view,
|
||||
show_num: show_num,
|
||||
});
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
carousel_change(e) {
|
||||
this.$emit('onCarouselChange', e.detail.current, this.propDataIndex);
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
233
components/diy/modules/data-magic/product-list-show.vue
Normal file
233
components/diy/modules/data-magic/product-list-show.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<view :class="['align-c flex-1 w h', (propOuterflex == 'row' ? 'flex-row' : 'flex-col')]" :style="'gap:' + propGoodStyle.data_goods_gap + 'px;'">
|
||||
<template v-if="propFlex === 'row'">
|
||||
<view v-for="(item, index) in propValue" :key="index" :style="block_size" class="w h">
|
||||
<view class="w h oh" :style="style_container">
|
||||
<view class="w h flex-row gap-10" :style="style_img_container" :data-index="index" :data-value="item.goods_url" @tap="url_event">
|
||||
<template v-if="!isEmpty(item.new_cover)">
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="!isEmpty(propIsShow)" class="flex-col w h tl jc-sb">
|
||||
<view v-if="propIsShow.includes('title')" class="text-line-2" :style="propGoodStyle.goods_title_style + 'height:'+ ((propGoodStyle.goods_title_size + 3) * 4) + 'rpx;'">{{ item.title || '' }}</view>
|
||||
<view v-if="propIsShow.includes('price')" :style="propGoodStyle.goods_price_style">
|
||||
<text :style="propGoodStyle.goods_price_symbol_style">{{ item.show_price_symbol || '' }}</text>
|
||||
{{ item.min_price || '' }}
|
||||
<template v-if="propIsShow.includes('price_unit')">
|
||||
<text :style="propGoodStyle.goods_price_unit_style">{{ item.show_price_unit || '' }}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="propFlex === 'col_price_float'">
|
||||
<view v-for="(item, index) in propValue" :key="index" :style="block_size" class="w h">
|
||||
<view class="w h oh" :style="style_container">
|
||||
<view class="w h flex-col gap-10" :style="style_img_container" :data-index="index" :data-value="item.goods_url" @tap="url_event">
|
||||
<view class="w h flex-1 pr oh">
|
||||
<template v-if="!isEmpty(item.new_cover)">
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="propIsShow.includes('price')" class="pa" :style="propGoodStyle.goods_price_style + float_pirce_style">
|
||||
<text :style="propGoodStyle.goods_price_symbol_style">{{ item.show_price_symbol || ''}}</text>{{ item.min_price || ''}}
|
||||
<template v-if="propIsShow.includes('price_unit')">
|
||||
<text :style="propGoodStyle.goods_price_unit_style">{{ item.show_price_unit || ''}}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="propIsShow.includes('title')" class="text-line-1 tl w" :style="propGoodStyle.goods_title_style + 'height:'+ ((propGoodStyle.goods_title_size + 3) * 2) + 'rpx;'">{{ item.title || '' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index) in propValue" :key="index" :style="block_size" class="w h">
|
||||
<view class="w h oh" :style="style_container">
|
||||
<view class="w h flex-col" :style="style_img_container" :data-index="index" :data-value="item.goods_url" @tap="url_event">
|
||||
<template v-if="!isEmpty(item.new_cover)">
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="!isEmpty(propIsShow)" class="flex-col w h tl jc-sb">
|
||||
<view v-if="propIsShow.includes('title')" class="text-line-2" :style="propGoodStyle.goods_title_style + 'height:'+ ((propGoodStyle.goods_title_size + 3) * 4) + 'rpx;'">{{ item.title || '' }}</view>
|
||||
<view v-if="propIsShow.includes('price')" :style="propGoodStyle.goods_price_style">
|
||||
<text :style="propGoodStyle.goods_price_symbol_style">{{ item.show_price_symbol || ''}}</text>{{ item.min_price || '' }}
|
||||
<template v-if="propIsShow.includes('price_unit')">
|
||||
<text :style="propGoodStyle.goods_price_unit_style">{{ item.show_price_unit || ''}}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { gradient_computer, radius_computer, padding_computer, background_computer, isEmpty, margin_computer, box_shadow_computer, border_computer, old_margin, old_border_and_box_shadow, old_padding } from "@/common/js/common/common.js";
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
propOuterflex: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propFlex: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propContentImgRadius: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propNum: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
propActived: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
propIsShow: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
propChunkPadding: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
propGoodStyle: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
block_size: '',
|
||||
float_pirce_style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
computed: {
|
||||
img_padding_computer() {
|
||||
if (!isEmpty(this.propChunkPadding)) {
|
||||
return padding_computer(this.propChunkPadding) + ';box-sizing: border-box;';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
if (!isEmpty(this.propGoodStyle)) {
|
||||
const { goods_color_list = [], goods_direction = '180deg', goods_radius = old_radius, goods_background_img = [], goods_background_img_style = '2', goods_chunk_padding = old_padding, goods_price_color_list = [], goods_price_direction = '180deg', goods_price_radius = old_radius, goods_price_padding = old_padding, goods_price_margin = old_margin, goods_price_location = 'center', goods_chunk_margin = old_margin} = this.propGoodStyle;
|
||||
const style_data = {
|
||||
color_list: goods_color_list,
|
||||
direction: goods_direction,
|
||||
}
|
||||
const style_img_data = {
|
||||
background_img: goods_background_img,
|
||||
background_img_style: goods_background_img_style,
|
||||
}
|
||||
|
||||
const data = {
|
||||
color_list: goods_price_color_list,
|
||||
direction: goods_price_direction,
|
||||
}
|
||||
let location = 'left:50%;transform:translateX(-50%);bottom:0;'
|
||||
if (goods_price_location == 'left') {
|
||||
location = 'left:0;bottom:0;';
|
||||
} else if (goods_price_location == 'right') {
|
||||
location = 'right:0;bottom:0;';
|
||||
}
|
||||
// 左右间距
|
||||
const shop_left_right_width_margin = goods_chunk_margin?.margin_left || 0 + goods_chunk_margin?.margin_right || 0;
|
||||
// 上下间距
|
||||
const shop_top_bottom_width_margin = goods_chunk_margin?.margin_top || 0 + goods_chunk_margin?.margin_bottom || 0;
|
||||
// 内容间距
|
||||
const total_gap = this.propGoodStyle.data_goods_gap * (this.propValue.length - 1);
|
||||
// 总的宽度
|
||||
const all_width = total_gap + (shop_left_right_width_margin.value * this.propNum);
|
||||
// 总的高度
|
||||
const all_height = total_gap + (shop_top_bottom_width_margin.value * this.propNum);
|
||||
this.setData({
|
||||
float_pirce_style: gradient_computer(data) + radius_computer(goods_price_radius) + padding_computer(goods_price_padding) + margin_computer(goods_price_margin) + location,
|
||||
style_container: gradient_computer(style_data) + radius_computer(goods_radius) + margin_computer(goods_chunk_margin) + border_computer(this.propGoodStyle) + box_shadow_computer(this.propGoodStyle), // 用于样式显示
|
||||
style_img_container: this.propFlex == 'col' ? background_computer(style_img_data) : padding_computer(goods_chunk_padding) + background_computer(style_img_data) + 'box-sizing: border-box;',
|
||||
block_size: this.propOuterflex == 'row' ? 'height:calc(100% - ' + shop_top_bottom_width_margin.value + 'px);width:calc((100% - ' + all_width + 'px) / ' + this.propNum + ');' : 'width:calc(100% - ' + shop_left_right_width_margin.value + 'px);height:calc((100% - ' + all_height + 'px) / ' + this.propNum + ');',
|
||||
});
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
url_event(e) {
|
||||
// 存储数据显示缓存
|
||||
let index = e.currentTarget.dataset.index || 0;
|
||||
let goods = this.propValue[index];
|
||||
app.globalData.goods_data_cache_handle(goods.id, goods);
|
||||
|
||||
this.$emit('url_event', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.w {
|
||||
width: 100%;
|
||||
}
|
||||
.h {
|
||||
height: 100%;
|
||||
}
|
||||
.half-width {
|
||||
width: 50%;
|
||||
}
|
||||
.gap-20 {
|
||||
gap: 40rpx;
|
||||
}
|
||||
</style>
|
||||
57
components/diy/modules/data-magic/video/index.vue
Normal file
57
components/diy/modules/data-magic/video/index.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<!-- 视频 -->
|
||||
<view class="video pr wh-auto ht-auto">
|
||||
<video :src="video" class="wh-auto ht-auto" :poster="video_img" objectFit="cover" :style="'object-fit: cover;' + video_style"></video>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { padding_computer, radius_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propDataStyle: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
video_img: '',
|
||||
video: '',
|
||||
video_style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue || {};
|
||||
// 视频比例
|
||||
this.setData({
|
||||
video_img: new_content.video_img.length > 0 ? new_content.video_img[0].url : '',
|
||||
video: new_content.video.length > 0 ? new_content.video[0].url : '',
|
||||
video_style: radius_computer(this.propDataStyle.img_radius),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
79
components/diy/modules/image-empty.vue
Normal file
79
components/diy/modules/image-empty.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<view :class="['oh img_wh', propClass]" :style="empty_outer_style + propStyle">
|
||||
<image :src="img_url" :mode="propImgFit" :style="empty_style + 'display: block;'" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { is_obj, isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propImageSrc: {
|
||||
type: [Object, String],
|
||||
default: () => {},
|
||||
},
|
||||
propErrorStyle: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propImgFit: {
|
||||
type: String,
|
||||
default: () => 'aspectFill',
|
||||
},
|
||||
propStyle: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propClass: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
empty_outer_style: '',
|
||||
empty_style: 'width: 100%; height: 100%;', // 有图片的时候显示为100%
|
||||
img_url: '',
|
||||
default_image: '/static/images/common/image-empty.png',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propImageSrc(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
let img_url = this.propImageSrc;
|
||||
if (is_obj(this.propImageSrc)) {
|
||||
img_url = !isEmpty(this.propImageSrc) ? this.propImageSrc.url : '';
|
||||
}
|
||||
// 没有图片的时候根据默认值来算
|
||||
if (img_url == undefined || img_url == null || img_url == '') {
|
||||
this.setData({
|
||||
empty_outer_style: 'background: #f4fcff;display:flex;align-items: center;justify-content: center;',
|
||||
empty_style: `${this.propErrorStyle}`,
|
||||
});
|
||||
img_url = this.default_image;
|
||||
} else {
|
||||
this.setData({
|
||||
empty_outer_style: '',
|
||||
empty_style: 'width: 100%; height: 100%;', // 有图片的时候显示为100%
|
||||
});
|
||||
}
|
||||
this.setData({
|
||||
img_url: img_url,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.img_wh {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
98
components/diy/modules/subscript/index.vue
Normal file
98
components/diy/modules/subscript/index.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<view v-if="form.seckill_subscript_show == '1'" class="corner-marker" :style="corner_marker">
|
||||
<view class="flex-row nowrap" :style="corner_img_marker">
|
||||
<template v-if="form.subscript_type == 'img-icon'">
|
||||
<template v-if="!isEmpty(form.subscript_img_src)">
|
||||
<image :src="form.subscript_img_src[0].url" mode="aspectFill" :style="img_style" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<iconfont :name="'icon-' + form.subscript_icon_class" propContainerDisplay="flex" :size="new_style.subscript_style.text_or_icon_size * 2 + 'rpx'" :color="new_style.subscript_style.text_or_icon_color"></iconfont>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="text-line-1" :style="text_size">{{ form.subscript_text }}</span>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_img_computer, common_styles_computer, isEmpty } from '@/common/js/common/common.js';
|
||||
import iconfont from '@/components/iconfont/iconfont';
|
||||
export default {
|
||||
components: {
|
||||
iconfont,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propType: {
|
||||
type: String,
|
||||
default: 'outer',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
corner_img_marker: '',
|
||||
img_style: '',
|
||||
text_size: '',
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
// 初始化数据
|
||||
init() {
|
||||
if (!isEmpty(this.propValue)) {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propType == 'outer' ? this.propValue.style || {} : { subscript_style: this.propValue.style || {} };
|
||||
if (!isEmpty(new_style.subscript_style)) {
|
||||
// 视频比例
|
||||
this.setData({
|
||||
form: new_content,
|
||||
new_style: new_style,
|
||||
corner_marker: this.get_corner_marker(new_style),
|
||||
text_size: `font-size: ${ new_style.subscript_style.text_or_icon_size * 2 }rpx;color: ${ new_style.subscript_style.text_or_icon_color };`,
|
||||
corner_img_marker: common_img_computer(new_style.subscript_style),
|
||||
img_style: `height: ${new_style.subscript_style.img_height * 2}rpx; width: ${new_style.subscript_style.img_width * 2}rpx`,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
get_corner_marker(new_style) {
|
||||
const { subscript_style } = new_style;
|
||||
let location = common_styles_computer(subscript_style);
|
||||
// 获取内部的显示数据
|
||||
const { seckill_subscript_location, top_or_bottom_spacing, left_or_right_spacing } = subscript_style;
|
||||
// 圆角根据图片的圆角来计算 对角线是同样的圆角
|
||||
if (seckill_subscript_location == 'top-left') {
|
||||
location += `top: ${ top_or_bottom_spacing * 2 }rpx;left: ${ left_or_right_spacing * 2 }rpx;`;
|
||||
} else if (seckill_subscript_location == 'top-center') {
|
||||
location += 'top: 0;left: 50%;transform: translateX(-50%);';
|
||||
} else if (seckill_subscript_location == 'top-right') {
|
||||
location += `top: ${ top_or_bottom_spacing * 2 }rpx;right:${ left_or_right_spacing * 2 }rpx;`;
|
||||
} else if (seckill_subscript_location == 'bottom-left') {
|
||||
location += `bottom: ${ top_or_bottom_spacing * 2 }rpx;left: ${ left_or_right_spacing * 2 }rpx;`;
|
||||
} else if (seckill_subscript_location == 'bottom-center') {
|
||||
location += 'bottom: 0;left: 50%;transform: translateX(-50%);';
|
||||
} else if (seckill_subscript_location == 'bottom-right') {
|
||||
location += `bottom: ${ top_or_bottom_spacing * 2 }rpx;right: ${ left_or_right_spacing * 2 }rpx;`;
|
||||
}
|
||||
return location;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.corner-marker {
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
592
components/diy/modules/tabs-view.vue
Normal file
592
components/diy/modules/tabs-view.vue
Normal file
@@ -0,0 +1,592 @@
|
||||
<template>
|
||||
<!-- 66rpx是自定义顶部导航栏的高度-->
|
||||
<view class="tabs-view" :style="tabs_sticky">
|
||||
<view class="tabs-view" :style="propStyle + propTabsBackground">
|
||||
<view class="pr" :style="propsTabsContainer">
|
||||
<view v-if="propIsRotatingBackground" class="pa top-0 wh-auto ht-auto" :style="propBgImgStyle"></view>
|
||||
<view class="flex-row gap-10 jc-sb align-c" :style="propsTabsImgContainer">
|
||||
<view class="tabs flex-1 flex-width">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" :scroll-with-animation="tabs_list_is_sliding_fixed" :scroll-left="scroll_left" :class="'wh-auto interior-area-' + propKey">
|
||||
<view :class="'flex-row ' + flex_class" :style="'height:' + tabs_height + ';width:' + tabs_scroll_width + 'px;'">
|
||||
<view v-for="(item, index) in tabs_list" :key="index" :class="'item nowrap flex-col jc-c align-c gap-4 scroll-item-' + propKey + ' ' + tabs_theme + (index == active_index ? ' active' : '') + ((tabs_theme_index == '0' && tabs_theme_1_style) || tabs_theme_index == '1' || tabs_theme_index == '2' ? ' pb-0' : '')" :style="'flex:0 0 auto;padding-left:' + (index == 0 ? '0' : tabs_spacing) + 'rpx;padding-right:' + (index + 1 == tabs_list.length ? '0' : tabs_spacing) + 'rpx;' + get_item_style(item.is_sliding_fixed)" :data-index="index" @tap="handle_event">
|
||||
<view class="nowrap ma-auto">
|
||||
<view v-if="tabs_theme_index == '4'" :class="'img oh pr z-i-deep ' + (!isEmpty(item.img) ? 'img-no-empty' : '')" :style="tabs_theme_style.tabs_top_img">
|
||||
<imageEmpty :propImageSrc="item.img[0]" propImgFit="aspectFit" propErrorStyle="width: 20rpx;height: 20rpx;"></imageEmpty>
|
||||
<!-- <image :src="item.img[0].url" class="img" mode="aspectFit" /> -->
|
||||
</view>
|
||||
<template v-if="item.tabs_type == '1'">
|
||||
<template v-if="!isEmpty(item.tabs_icon)">
|
||||
<view :class="tabs_theme_index == '4' ? 'title pr z-i' : 'title pr z-i-deep'" :style="(tabs_theme_index == '4' ? tabs_sign_spacing : '') + (index == active_index ? (['2', '4'].includes(tabs_theme_index) ? tabs_check : '') : '' + tabs_padding_bottom)">
|
||||
<iconfont :name="'icon-' + item.tabs_icon" :color="index == active_index ? tabs_icon_checked_color : tabs_icon_color" propContainerDisplay="flex" :size="index == active_index ? tabs_icon_checked_size : tabs_icon_size"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :class="tabs_theme_index == '4' ? 'title pr z-i' : 'title pr z-i-deep'" :style="(tabs_theme_index == '4' ? tabs_sign_spacing : '') + index == active_index ? new_style.is_tabs_img_background == '1' && ['2', '4'].includes(tabs_theme_index) ? tabs_check : '' : tabs_padding_bottom">
|
||||
<imageEmpty :propImageSrc="item.tabs_img[0]" :propStyle="index == active_index ? tabs_theme_style.tabs_img_checked : tabs_theme_style.tabs_img" propImgFit="heightFix" propErrorStyle="width: 40rpx;height: 40rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :class="tabs_theme_index == '4' ? 'title pr z-i' : 'title pr z-i-deep'" :style="(tabs_theme_index == '4' ? tabs_sign_spacing : '') + (index == active_index ? ['2', '4'].includes(tabs_theme_index) ? tabs_theme_style.tabs_title_checked + tabs_check : tabs_theme_style.tabs_title_checked : tabs_theme_style.tabs_title + tabs_padding_bottom)">{{ item.title }}</view>
|
||||
</template>
|
||||
<view class="desc pr z-i wh-auto" :style="tabs_sign_spacing + (tabs_theme_index == '1' && index == active_index ? tabs_check : '')">{{ item.desc }}</view>
|
||||
<template v-if="tabs_theme_index == '3' && index == active_index">
|
||||
<template v-if="!isEmpty(form.tabs_adorn_icon)">
|
||||
<view class="icon pr z-i wh-auto flex-row jc-c align-c" :style="tabs_sign_spacing">
|
||||
<iconfont :name="'icon-' + form.tabs_adorn_icon" :style="icon_tabs_check" propContainerDisplay="flex" :size="tabs_adorn_icon_size"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="pr z-i wh-auto flex-row jc-c align-c ma-auto" :style="tabs_sign_spacing">
|
||||
<imageEmpty :propImageSrc="form.tabs_adorn_img[0]" :propStyle="tabs_adorn_img_style" propImgFit="aspectFit" propErrorStyle="width: 20rpx;height: 20rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
<view class="bottom_line z-i" :class="tabs_bottom_line_theme" :style="tabs_check + tabs_sign_spacing"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view v-if="propIsTabsIcon && form.show_more !== '0'" :style="tabs_padding_bottom">
|
||||
<iconfont :name="'icon-' + icon.more_icon_class || 'category-more'" :size="icon.more_icon_size + '' || '14'" :color="icon.more_icon_color || '#000'" propContainerDisplay="flex" @click="category_check_event"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 选项卡更多弹窗 -->
|
||||
<componentPopup :propShow="popup_status" :propIsBar="propIsBar" propPosition="top" :propMask="true" :propTop="newPropTop" :propStyle="newPropStyle" @onclose="quick_close_event">
|
||||
<view :class="'padding-bottom-lg ' + (['toutiao', 'app', 'h5'].includes(platform) ? 'padding-top-lg' : 'padding-top')">
|
||||
<view class="padding-left-main padding-bottom-main">全部选项卡</view>
|
||||
<view class="divider-b">
|
||||
<view class="nav-list-more">
|
||||
<view class="flex-row flex-wrap align-c">
|
||||
<view v-for="(item, index) in tabs_list" :key="index" class="item tc cr-base cp text-size-xs" :data-index="index" @tap="handle_event">
|
||||
<view class="dis-inline-block padding-vertical-xs padding-horizontal round" :class="active_index == index ? 'bg-main border-color-main cr-white' : ''">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tc padding-top-lg flex-row jc-c align-c" @tap="quick_close_event">
|
||||
<text class="padding-right-sm">{{ $t('nav-more.nav-more.h9g4b1') }}</text>
|
||||
<iconfont name="icon-arrow-top" color="#ccc" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</componentPopup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { gradient_computer, isEmpty, radius_computer } from '@/common/js/common/common.js';
|
||||
import componentPopup from '@/components/popup/popup';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
components: {
|
||||
componentPopup,
|
||||
imageEmpty,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
// 是否需要icon
|
||||
propIsTabsIcon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否需要粘性定位置顶
|
||||
propIsTop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 指定样式
|
||||
propStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 层级
|
||||
propZIndex: {
|
||||
type: Number,
|
||||
default: 11,
|
||||
},
|
||||
// 自定义导航栏高度
|
||||
propCustomNavHeight: {
|
||||
type: String,
|
||||
default: '66rpx',
|
||||
},
|
||||
// tabs背景色
|
||||
propTabsBackground: {
|
||||
type: String,
|
||||
default: 'transparent',
|
||||
},
|
||||
// 置顶距离顶部高度
|
||||
propTop: {
|
||||
type: [String, Number],
|
||||
default: '0',
|
||||
},
|
||||
propsTabsContainer: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propsTabsImgContainer: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIsRotatingBackground: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propBgImgStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propTabsSlidingFixedBg: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
tabs_theme_index: '',
|
||||
tabs_theme: '',
|
||||
tabs_check: '',
|
||||
icon_tabs_check: '',
|
||||
tabs_spacing: '',
|
||||
tabs_sign_spacing: '',
|
||||
tabs_padding_bottom: '',
|
||||
tabs_list: [],
|
||||
active_index: 0,
|
||||
tabs_theme_style: {
|
||||
tabs_title_checked: '',
|
||||
tabs_title: '',
|
||||
tabs_img_checked: '',
|
||||
tabs_img: '',
|
||||
tabs_top_img: ''
|
||||
},
|
||||
tabs_icon_checked_size: '',
|
||||
tabs_icon_size: '',
|
||||
tabs_icon_checked_color: '',
|
||||
tabs_icon_color: '',
|
||||
icon: {
|
||||
more_icon_class: '',
|
||||
more_icon_size: '',
|
||||
more_icon_color: '',
|
||||
},
|
||||
// 过滤弹窗
|
||||
popup_status: false,
|
||||
propIsBar: false,
|
||||
tabs_bottom_line_theme: '',
|
||||
tabs_sticky: '',
|
||||
tabs_height: '100%',
|
||||
tabs_adorn_img_style: '',
|
||||
tabs_width: 0,
|
||||
tabs_scroll_width: 0,
|
||||
// #ifdef MP
|
||||
sticky_top: bar_height,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
sticky_top: bar_height,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
sticky_top: bar_height,
|
||||
// #endif
|
||||
newPropTop: '',
|
||||
newPropStyle: '',
|
||||
platform: app.globalData.application_client_type(),
|
||||
is_out_of_range: false,
|
||||
tabs_list_is_sliding_fixed: true,
|
||||
scroll_left: 0,
|
||||
tabs_adorn_icon_size: '0rpx',
|
||||
// 默认数据
|
||||
old_radius: { radius: 0, radius_top_left: 0, radius_top_right: 0, radius_bottom_left: 0, radius_bottom_right: 0 },
|
||||
old_padding: { padding: 0, padding_top: 0, padding_bottom: 0, padding_left: 0, padding_right: 0 },
|
||||
old_margin: { margin: 0, margin_top: 10, margin_bottom: 0, margin_left: 0, margin_right: 0 },
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
flex_class() {
|
||||
if (this.is_out_of_range) {
|
||||
return this.form.justification == 'center' ? 'jc-c' : this.form.justification == 'right' ? 'jc-e': '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
get_item_style() {
|
||||
return (val) => {
|
||||
return val == '1' ? `${ this.propTabsSlidingFixedBg };position: sticky;left: 0;z-index: 11;` : ''
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
propValue() {
|
||||
this.init();
|
||||
},
|
||||
propIsTop: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler(new_val) {
|
||||
if (new_val) {
|
||||
this.tabs_sticky = 'position: sticky;top: calc(' + parseInt(this.propTop) + 'px + ' + this.propCustomNavHeight + ');z-index: ' + this.propZIndex + ';';
|
||||
} else {
|
||||
this.tabs_sticky = '';
|
||||
}
|
||||
},
|
||||
},
|
||||
propTop(new_val, old_val) {
|
||||
if (this.propIsTop) {
|
||||
this.tabs_sticky = 'position: sticky;top: calc(' + parseInt(this.propTop) + 'px + ' + this.propCustomNavHeight + ');z-index: ' + this.propZIndex + ';';
|
||||
} else {
|
||||
this.tabs_sticky = '';
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 判断是否为空
|
||||
isEmpty,
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
const new_tabs_check = this.tabs_check_computer(new_style);
|
||||
const new_icon = {
|
||||
more_icon_class: new_style.more_icon_class,
|
||||
more_icon_size: new_style.more_icon_size,
|
||||
more_icon_color: new_style.more_icon_color,
|
||||
};
|
||||
const tabs_top_img_height = new_style?.tabs_top_img_height || 39;
|
||||
const tabs_top_img_radius = new_style?.tabs_top_img_radius || { radius: 100, radius_top_left: 100, radius_top_right: 100, radius_bottom_left: 100, radius_bottom_right: 100}
|
||||
// 标题样式
|
||||
const new_tabs_theme_style = {
|
||||
tabs_title_checked: `font-weight: ${new_style.tabs_weight_checked};font-size: ${new_style.tabs_size_checked * 2}rpx;line-height: ${new_style.tabs_size_checked * 2}rpx;color:${new_style.tabs_color_checked};`,
|
||||
tabs_title: `font-weight: ${new_style.tabs_weight};font-size: ${new_style.tabs_size * 2}rpx;line-height: ${new_style.tabs_size * 2}rpx;color:${new_style.tabs_color};`,
|
||||
tabs_img_checked: `height: ${(new_style?.tabs_img_height || 0) * 2}rpx;` + radius_computer(new_style?.tabs_img_radius || this.old_radius),
|
||||
tabs_img: `height: ${(new_style?.tabs_img_height || 0) * 2}rpx;` + radius_computer(new_style?.tabs_img_radius || this.old_radius),
|
||||
tabs_top_img: `height: ${tabs_top_img_height * 2 }rpx;width: ${tabs_top_img_height * 2 }rpx;box-sizing: border-box;` + radius_computer(tabs_top_img_radius),
|
||||
};
|
||||
const { tabs_size_checked, tabs_size, tabs_icon_size_checked = 0, tabs_icon_size = 0, tabs_img_height = 0, tabs_sign_spacing = 0 } = new_style || {};
|
||||
let default_height = 0;
|
||||
if (new_content.tabs_theme == '2') {
|
||||
default_height = 12; // 选中的时候,风格二的内间距
|
||||
} else if (new_content.tabs_theme == '4') {
|
||||
// const top_index = new_content?.tabs_list?.findIndex((item) => !isEmpty(item.img)) ?? -1;
|
||||
// default_height = 4 + (top_index > -1 ? tabs_top_img_height + tabs_sign_spacing : 0); // 选中的时候,风格二的内间距 加上上边图片的大小和上边图片之间的间距
|
||||
default_height = 4 + tabs_top_img_height + tabs_sign_spacing;
|
||||
}
|
||||
// 筛选出所有的icon
|
||||
const is_icon = new_content?.tabs_list?.findIndex((item) => item.tabs_type === '1' && !isEmpty(item.tabs_icon)) ?? -1;
|
||||
// 如果有icon,则取选中的icon大小和未选中的icon大小取最大值,作为图标的高度
|
||||
let icon_height = 0;
|
||||
if (is_icon > -1) {
|
||||
icon_height = Math.max(tabs_icon_size_checked + default_height, tabs_icon_size);
|
||||
}
|
||||
// 筛选出所有的图片, 没有选择图标的时候默认是图片
|
||||
const is_img = new_content?.tabs_list?.findIndex((item) => item.tabs_type === '1' && isEmpty(item.tabs_icon)) ?? -1;
|
||||
// 选项卡高度 五个值,作为判断依据,因为图片没有未选中的大小设置,所以高度判断的时候只取选中的高度, 其余的icon和标题都分别取选中和未选中的大小对比,取出最大的值,作为选项卡的高度,避免选项卡切换时会出现抖动问题
|
||||
const height = Math.max(tabs_size_checked + default_height, tabs_size, icon_height, is_img > -1 ? (tabs_img_height + default_height) : '');
|
||||
const findIndex = new_content.tabs_list.findIndex(item => item.is_sliding_fixed == '1');
|
||||
// 参数设置
|
||||
this.setData({
|
||||
form: new_content,
|
||||
tabs_list_is_sliding_fixed: findIndex == -1,
|
||||
newPropTop: `calc(${ this.sticky_top * 2}rpx);`,
|
||||
newPropStyle: `padding-top: ${ this.sticky_top * 2 }rpx;margin-top: -${ this.sticky_top * 2 }rpx;`,
|
||||
new_style: new_style,
|
||||
tabs_spacing: Number(new_style.tabs_spacing),
|
||||
tabs_sign_spacing: !isEmpty(new_style.tabs_sign_spacing) ? `margin-top: ${new_style.tabs_sign_spacing * 2}rpx;` : 'margin-top: 8rpx;',
|
||||
tabs_list: new_content.tabs_list,
|
||||
tabs_padding_bottom: this.get_padding_bottom(new_content, new_style) + 'z-index: 11;',
|
||||
// 选项卡主题
|
||||
tabs_theme: this.get_tabs_theme(new_content),
|
||||
tabs_theme_index: new_content.tabs_theme,
|
||||
// 选项卡样式
|
||||
tabs_check: new_tabs_check,
|
||||
icon_tabs_check: `${new_tabs_check};line-height: 1;background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;`,
|
||||
icon: new_icon,
|
||||
tabs_icon_checked_size: (new_style?.tabs_icon_size_checked || 0) * 2 + 'rpx',
|
||||
tabs_icon_size: (new_style?.tabs_icon_size || 0) * 2 + 'rpx',
|
||||
tabs_icon_checked_color: new_style?.tabs_icon_color_checked || '',
|
||||
tabs_icon_color: new_style?.tabs_icon_color || '',
|
||||
tabs_theme_style: new_tabs_theme_style,
|
||||
tabs_bottom_line_theme: new_style.tabs_one_theme == '1' ? 'tabs-bottom-line-theme' : '',
|
||||
tabs_theme_1_style: new_style.tabs_one_theme == '1',
|
||||
tabs_height: ['2', '4'].includes(new_content.tabs_theme) ? height * 2 + 'rpx' : '100%;',
|
||||
tabs_adorn_img_style: this.get_tabs_adorn_img_style(new_style),
|
||||
tabs_adorn_icon_size: (new_style?.tabs_adorn_icon_size || 0) * 2 + 'rpx',
|
||||
});
|
||||
// 只有居中居右的才重新获取dom判断
|
||||
// if (['center', 'right'].includes(this.form.justification)) {
|
||||
setTimeout(() => {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('.interior-area-' + this.propKey)
|
||||
.fields({ size: true, scrollOffset: true},(res) => {
|
||||
if ((res || null) != null) {
|
||||
const { scrollWidth, width } = res;
|
||||
this.setData({
|
||||
is_out_of_range: scrollWidth <= width,
|
||||
tabs_scroll_width: scrollWidth,
|
||||
tabs_width: width
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
}, 0)
|
||||
// }
|
||||
},
|
||||
get_tabs_adorn_img_style(new_style) {
|
||||
return radius_computer(new_style?.tabs_adorn_img_radius || this.old_radius) + `height: ${(new_style?.tabs_adorn_img_height || 10) * 2}rpx;${ new_style.is_tabs_adorn_img_background == '1' ? tabs_check.value : ''}`;
|
||||
},
|
||||
// 获取选项卡主题
|
||||
get_tabs_theme(data) {
|
||||
let arr = {
|
||||
1: 'tabs-style-2',
|
||||
2: 'tabs-style-3',
|
||||
3: 'tabs-style-4',
|
||||
4: 'tabs-style-5',
|
||||
};
|
||||
let value = arr[data.tabs_theme];
|
||||
return value === undefined ? 'tabs-style-1' : value;
|
||||
},
|
||||
get_padding_bottom(form, new_style) {
|
||||
let bottom = 0;
|
||||
if (form.tabs_theme == '0') {
|
||||
if (new_style.tabs_one_theme == '1') {
|
||||
bottom = 6;
|
||||
} else {
|
||||
bottom = 3;
|
||||
}
|
||||
} else if (form.tabs_theme == '3') {
|
||||
bottom = !isEmpty(form.tabs_adorn_icon) ? new_style.tabs_adorn_icon_size : new_style.tabs_adorn_img_height;
|
||||
}
|
||||
const tabs_sign_spacing = !isEmpty(new_style.tabs_sign_spacing) ? new_style.tabs_sign_spacing : 4;
|
||||
return ['1', '2', '4'].includes(form.tabs_theme) ? '' : `padding-bottom: ${(tabs_sign_spacing + bottom) * 2 }rpx;`;
|
||||
},
|
||||
// 选中的背景渐变色样式
|
||||
tabs_check_computer(data) {
|
||||
const new_gradient_params = {
|
||||
color_list: data.tabs_checked,
|
||||
direction: data.tabs_direction,
|
||||
};
|
||||
return gradient_computer(new_gradient_params);
|
||||
},
|
||||
|
||||
// 事件
|
||||
// tabs切换事件
|
||||
handle_event(e) {
|
||||
const index = e.currentTarget.dataset.index;
|
||||
const tabs_list_item = this.tabs_list[index];
|
||||
this.setData({
|
||||
active_index: index,
|
||||
popup_status: false,
|
||||
});
|
||||
this.set_scoll_left(index);
|
||||
this.$emit('onTabsTap', index, tabs_list_item);
|
||||
setTimeout(() => {
|
||||
this.$emit('tabsZindex', 11)
|
||||
}, 200)
|
||||
},
|
||||
// 将选中的内容定位到中间
|
||||
set_scoll_left(index) {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.selectAll(`.scroll-item-` + this.propKey)
|
||||
.boundingClientRect((rect) => {
|
||||
const tabs_index = this.form.tabs_list.findIndex(item => item.is_sliding_fixed == '1');
|
||||
// 如果第一个悬浮了,就取第二个的left加上 第一个的宽度和left
|
||||
let new_width = tabs_index == 0 && index != 0 ? rect[1].left - rect[0].width - rect[0].left : rect[0].left;
|
||||
// 如果悬浮的不是第一个并且选中的是悬浮的内容
|
||||
if (index > 0 && tabs_index == index) {
|
||||
new_width = rect[0].left - rect[index + 1].left + rect[index].width;
|
||||
}
|
||||
const scrollLeft =
|
||||
rect[index].left +
|
||||
rect[index].width / 2 -
|
||||
this.tabs_width / 2 -
|
||||
new_width
|
||||
this.setData({
|
||||
scroll_left: scrollLeft,
|
||||
});
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
// 分类选择事件
|
||||
category_check_event() {
|
||||
this.setData({
|
||||
popup_status: true,
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.$emit('tabsZindex', 13)
|
||||
}, 0)
|
||||
},
|
||||
// 关闭分类选择事件
|
||||
quick_close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.$emit('tabsZindex', 11)
|
||||
}, 200)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tabs {
|
||||
.item {
|
||||
// padding: 0 0 10rpx 0;
|
||||
position: relative;
|
||||
&:first-of-type {
|
||||
margin-left: 0;
|
||||
}
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.desc {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
.bottom_line {
|
||||
width: 100%;
|
||||
height: 6rpx;
|
||||
border-radius: 20rpx;
|
||||
background-color: red;
|
||||
// position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: none;
|
||||
}
|
||||
.icon {
|
||||
// position: absolute;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
font-size: 40rpx;
|
||||
line-height: 20rpx !important;
|
||||
display: none;
|
||||
}
|
||||
.img {
|
||||
// width: 78rpx;
|
||||
// height: 78rpx;
|
||||
border-radius: 100%;
|
||||
border: 2rpx solid transparent;
|
||||
display: none;
|
||||
margin: 0 auto;
|
||||
}
|
||||
&.tabs-style-1 {
|
||||
&.active {
|
||||
.bottom_line {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.tabs-bottom-line-theme {
|
||||
opacity: 0.6;
|
||||
bottom: 0;
|
||||
z-index: 0;
|
||||
height: 14rpx;
|
||||
border-radius: 0;
|
||||
// left: 12%;
|
||||
}
|
||||
}
|
||||
&.tabs-style-2 {
|
||||
&.active {
|
||||
.desc {
|
||||
background: #ff5e5e;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.desc {
|
||||
border-radius: 40rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&.tabs-style-3 {
|
||||
&.active {
|
||||
.title {
|
||||
// background: #ff2222;
|
||||
border-radius: 40rpx;
|
||||
padding: 6px 12px;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.tabs-style-4 {
|
||||
// padding-bottom: 28rpx;
|
||||
&.active {
|
||||
.title {
|
||||
color: #ff2222;
|
||||
}
|
||||
.icon {
|
||||
color: #ff2222;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.tabs-style-5 {
|
||||
align-items: center;
|
||||
&.active {
|
||||
.title {
|
||||
// font-size: 22rpx;
|
||||
// background: #ff5e5e;
|
||||
border-radius: 40rpx;
|
||||
padding: 2px 7px;
|
||||
box-sizing: border-box;
|
||||
// color: #fff;
|
||||
}
|
||||
.img {
|
||||
border-color: #ff5e5e;
|
||||
}
|
||||
}
|
||||
.img-no-empty {
|
||||
width: 100% !important;
|
||||
}
|
||||
.img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.nav-list-more {
|
||||
width: 100%;
|
||||
max-height: 550rpx;
|
||||
padding-bottom: 20rpx;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.nav-list-more .item {
|
||||
width: 20%;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
.pb-14 {
|
||||
padding-bottom: 28rpx;
|
||||
}
|
||||
.pb-0 {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
.ma-auto {
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
248
components/diy/nav-group.vue
Normal file
248
components/diy/nav-group.vue
Normal file
@@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view class="pr" :style="style_img_container">
|
||||
<swiper class="swiper" circular="true" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_group" :style="{ height: new_height }" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in nav_content_list" :key="index" class="swiper-item">
|
||||
<view class="banner-img flex-row flex-wrap wh-auto" :class="'banner-img-' + propKey" :style="space">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1" class="flex-col gap-10 align-c" :style="group_width + nav_title_space" :data-value="item1.link.page" @tap="url_open_event">
|
||||
<view v-if="['image_with_text', 'image'].includes(nav_style)" class="flex-row align-c jc-c pr">
|
||||
<view class="top-img" :style="img_size">
|
||||
<imageEmpty :propImageSrc="item1.img[0]" :propStyle="img_style" propErrorStyle="width: 60rpx;height: 60rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="item1.subscript" propType="nav-group"></subscriptIndex>
|
||||
</view>
|
||||
<view v-if="['image_with_text', 'text'].includes(nav_style)" class="wh-auto size-12 ma-0 nowrap oh tc" :style="text_style">{{ item1.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-if="form.display_style == 'slide' && new_style.is_show == '1'" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
|
||||
<block v-if="new_style.indicator_style == 'num'">
|
||||
<view :style="indicator_style" class="dot-item">
|
||||
<text :style="{ color: new_style.actived_color }">{{ actived_index + 1 }}</text>
|
||||
<text>/{{ nav_content_list.length }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-for="(item, index) in nav_content_list" :key="index" :style="indicator_style + (actived_index == index ? 'background:' + new_style.actived_color : '')" class="dot-item" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty, common_styles_computer, common_img_computer, radius_computer, padding_computer, get_indicator_style, get_indicator_location_style } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import subscriptIndex from '@/components/diy/modules/subscript/index.vue';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
subscriptIndex,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
img_style: '',
|
||||
text_style: '',
|
||||
indicator_style: '',
|
||||
new_height: '300rpx',
|
||||
actived_index: 0,
|
||||
group_width: '',
|
||||
nav_content_list: [],
|
||||
nav_title_space: 'row-gap:20rpx', // 导航标题间距
|
||||
space: 'row-gap:20rpx', // 导航间距
|
||||
img_size: '72rpx',
|
||||
slides_per_group: 1,
|
||||
indicator_location_style: '',
|
||||
subscriptStyle: {
|
||||
seckill_subscript_location: 'top-left',
|
||||
text_or_icon_color: '#fff',
|
||||
text_or_icon_size: 12,
|
||||
img_width: 20,
|
||||
img_height: 20,
|
||||
direction: '90deg',
|
||||
top_or_bottom_spacing: 0,
|
||||
left_or_right_spacing: 0,
|
||||
color_list: [{ color: '#FF7607', color_percentage: undefined }],
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
radius: 4,
|
||||
radius_top_left: 4,
|
||||
radius_top_right: 4,
|
||||
radius_bottom_left: 4,
|
||||
radius_bottom_right: 4,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
box_shadow_color: '',
|
||||
box_shadow_x: 0,
|
||||
box_shadow_y: 0,
|
||||
box_shadow_blur: 0,
|
||||
box_shadow_spread: 0,
|
||||
}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_content = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
|
||||
let group = 1;
|
||||
let group_width = `width: ${100 / (new_content.single_line || 4)}%;`;
|
||||
// 判断是否是轮播图
|
||||
if (new_content?.display_style == 'slide') {
|
||||
if (new_content.row == 1 && new_style.rolling_fashion == 'translation') {
|
||||
group = new_content.single_line || 4;
|
||||
group_width = 'width: 100%;';
|
||||
} else {
|
||||
group = 1;
|
||||
group_width = `width: ${100 / (new_content.single_line || 4)}%;`;
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
form: new_content,
|
||||
new_style: new_style,
|
||||
style_container: common_styles_computer(new_style.common_style), // 用于样式显示
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
img_style: radius_computer(new_style), // 图片的设置
|
||||
text_style: `font-size: ${new_style.title_size * 2 || 24}rpx; color: ${new_style.title_color || '#000'};`, // 标题的样式
|
||||
indicator_style: get_indicator_style(new_style), // 指示器的样式
|
||||
indicator_location_style: get_indicator_location_style(new_style), // 指示器位置处理
|
||||
actived_color: new_style.actived_color || '#2A94FF', // 轮播图显示样式
|
||||
slides_per_group: group, // 每个轮播图显示的个数
|
||||
group_width: group_width, // 每个导航所占位置
|
||||
nav_title_space: 'row-gap:' + (new_style.title_space || 0) * 2 + 'rpx', // 导航标题间距
|
||||
space: 'row-gap:' + (new_style.space || 0) * 2 + 'rpx;' + padding_computer(new_style.data_padding), // 导航间距
|
||||
img_size: 'width:' + (new_style.img_size || 0) * 2 + 'rpx;height:' + (new_style.img_size || 0) * 2 + 'rpx;', // 图片大小
|
||||
nav_style: new_content.nav_style || 'image_with_text', // 是否显示文字和图片
|
||||
nav_content_list: this.get_nav_content_list(new_content, new_style),
|
||||
});
|
||||
setTimeout(() => {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
// 选择我们想要的元素
|
||||
query
|
||||
.select('.banner-img-' + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
// data包含元素的宽度、高度等信息
|
||||
this.setData({
|
||||
new_height: res.height + 'px',
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec(); // 执行查询
|
||||
}, 50);
|
||||
},
|
||||
get_nav_content_list(data, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const list = JSON.parse(JSON.stringify(data.nav_content_list || Array(4))).map(item => ({
|
||||
...item,
|
||||
// 角标配置
|
||||
subscript: isEmpty(item.subscript) ?
|
||||
{
|
||||
content: {
|
||||
seckill_subscript_show: '0',
|
||||
subscript_type: 'text',
|
||||
subscript_img_src: [],
|
||||
subscript_icon_class: '',
|
||||
subscript_text: '',
|
||||
},
|
||||
style: this.subscriptStyle,
|
||||
} : item.subscript,
|
||||
}));
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (list.length > 0 && data.display_style == 'slide') {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
if (data.row == 1 && new_style.rolling_fashion == 'translation') {
|
||||
// 拆分的数量
|
||||
list.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
} else {
|
||||
// 每页显示的数量
|
||||
const num = (data.single_line || 4) * (data.row || 1);
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(list.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: list.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
}
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: list,
|
||||
},
|
||||
];
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
this.setData({
|
||||
actived_index: e.detail.current,
|
||||
});
|
||||
},
|
||||
url_open_event(link) {
|
||||
app.globalData.url_event(link);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.top-img {
|
||||
height: 72rpx;
|
||||
width: 72rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.gap-x-10 {
|
||||
row-gap: 20rpx;
|
||||
}
|
||||
</style>
|
||||
211
components/diy/notice.vue
Normal file
211
components/diy/notice.vue
Normal file
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<!-- 公告 -->
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<template v-if="form_content.notice_style == 'inherit'">
|
||||
<view class="news-box" :style="container_background_style + container_height">
|
||||
<view class="flex-row align-c gap-8" :style="container_background_img_style">
|
||||
<template v-if="form_content.title_type == 'img-icon'">
|
||||
<view v-if="form_content.icon_class">
|
||||
<iconfont :name="'icon-' + form_content.icon_class" :size="form_style.icon_size * 2 + 'rpx'" :color="form_style.icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
<view v-else>
|
||||
<image v-if="form_content.img_src.length > 0" :src="form_content.img_src[0].url" class="border-radius-sm dis-block" mode="aspectFill" :style="img_style"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :style="title_style" class="padding-horizontal-sm border-radius-sm">{{ form_content.title || '公告' }}</view>
|
||||
</template>
|
||||
<swiper class="swiper flex-1" circular :indicator-dots="false" :autoplay="true" :interval="interval_time" :vertical="direction_type == 'vertical'" :style="container_height">
|
||||
<swiper-item v-for="(item, index) in notice_list" :key="index">
|
||||
<view class="swiper-item flex-row align-c ht-auto" :style="content_title_style + 'color:' + form_style.news_color" :data-value="item.notice_link.page" @tap="url_event">
|
||||
<view class="text-line-1">{{ item.notice_title }}</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-if="form_content.is_right_button == '1'" class="flex-row align-c" :style="'color: ' + form_style.right_button_color + ';font-size:' + form_style.right_button_size * 2 + 'rpx;'" :data-value="form_content.more_link.page" @tap="url_event">
|
||||
{{ form_content.right_title }}
|
||||
<view class="pr">
|
||||
<iconfont name="icon-arrow-right" :color="form_style.right_button_color || '#999'" :size="form_style.right_button_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="news-card" :style="container_background_style">
|
||||
<view class="flex-col gap-10" :style="container_background_img_style">
|
||||
<view class="flex-row wh-auto jc-sb align-c">
|
||||
<template v-if="form_content.title_type == 'img-icon'">
|
||||
<template v-if="form_content.icon_class">
|
||||
<iconfont :name="'icon-' + form_content.icon_class" :size="form_style.icon_size * 2 + 'rpx'" :color="form_style.icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</template>
|
||||
<template v-else>
|
||||
<image v-if="form_content.img_src.length > 0" :src="form_content.img_src[0].url" class="border-radius-sm dis-block" mode="aspectFill" :style="img_style"></image>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :style="title_style" class="padding-horizontal-sm border-radius-sm">{{ form_content.title }}</view>
|
||||
</template>
|
||||
<view v-if="form_content.is_right_button == '1'" class="flex-row align-c" :style="'color: ' + form_style.right_button_color + ';font-size:' + form_style.right_button_size * 2 + 'rpx;'" :data-value="form_content.more_link.page" @tap="url_event">
|
||||
{{ form_content.right_title }}
|
||||
<view class="pr">
|
||||
<iconfont name="icon-arrow-right" :color="form_style.right_button_color || '#999'" :size="form_style.right_button_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(item, index) in notice_list" :key="index" class="flex-row" :style="content_title_style" :data-value="item.notice_link.page" @tap="url_event">
|
||||
<view class="num" :class="'one' + (index + 1)">{{ index + 1 }}</view>
|
||||
<view class="break" :style="'color:' + form_style.news_color">{{ item.notice_title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, gradient_handle, radius_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form_content: {},
|
||||
form_style: {},
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
// 容器高度
|
||||
container_height: '',
|
||||
// 容器背景
|
||||
container_background_style: '',
|
||||
// 图片设置
|
||||
img_style: '',
|
||||
// 标题的设置
|
||||
title_style: '',
|
||||
// 内容标题设置
|
||||
content_title_style: '',
|
||||
// 指示器的样式
|
||||
// 轮播图定时显示
|
||||
interval_time: 2000,
|
||||
// 轮播图滚动方向 // vertical' | 'horizontal
|
||||
direction_type: 'vertical',
|
||||
// 记录当前显示的轮播图的数据
|
||||
interval_list: {
|
||||
time: 2000,
|
||||
direction: 'vertical',
|
||||
notice_length: 1,
|
||||
},
|
||||
// 公告数据
|
||||
notice_list: [],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
// 容器背景
|
||||
const { container_color_list, container_direction, container_background_img_style, container_background_img } = new_style;
|
||||
const temp_obj = {
|
||||
color_list: container_color_list,
|
||||
direction: container_direction,
|
||||
background_img: container_background_img,
|
||||
background_img_style: container_background_img_style,
|
||||
};
|
||||
const temp_container_background_style = gradient_computer(temp_obj) + radius_computer(new_style.container_radius) + `overflow:hidden;`;
|
||||
const temp_container_background_img_style = background_computer(temp_obj);
|
||||
// 标题渐变色处理
|
||||
const gradient = gradient_handle(new_style.title_color_list, '90deg');
|
||||
const time = (new_style.interval_time || 2) * 1000;
|
||||
const direction = new_content.direction;
|
||||
const new_notice_list = new_content.notice_list.filter((item) => item.is_show == '1');
|
||||
// 判断长度是否相等
|
||||
const notice_length = new_notice_list.length;
|
||||
const new_interval_list = {
|
||||
time: time,
|
||||
direction: direction,
|
||||
notice_length: notice_length,
|
||||
};
|
||||
this.setData({
|
||||
form_content: new_content,
|
||||
form_style: new_style,
|
||||
container_height: 'height:' + new_style.container_height * 2 + 'rpx',
|
||||
container_background_style: temp_container_background_style,
|
||||
container_background_img_style: temp_container_background_img_style,
|
||||
img_style: `height: ${new_style.title_height * 2}rpx; width: ${new_style.title_width * 2}rpx`,
|
||||
title_style: `color:${new_style.title_color}; font-size: ${new_style.title_size * 2}rpx; font-weight: ${new_style.title_typeface}; ${gradient}`,
|
||||
content_title_style: `font-size: ${new_style.news_size * 2}rpx; font-weight: ${new_style.news_typeface};`,
|
||||
notice_list: new_notice_list,
|
||||
interval_time: time,
|
||||
direction_type: direction,
|
||||
interval_list: new_interval_list,
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.news-box {
|
||||
overflow: hidden;
|
||||
padding: 0 20rpx;
|
||||
background: #fff;
|
||||
}
|
||||
.news-card {
|
||||
padding: 30rpx;
|
||||
background: #fff;
|
||||
}
|
||||
.num {
|
||||
padding-right: 14rpx;
|
||||
color: #999;
|
||||
}
|
||||
.one1 {
|
||||
color: #ea3323;
|
||||
}
|
||||
.one2 {
|
||||
color: #ff7303;
|
||||
}
|
||||
.one3 {
|
||||
color: #ffc300;
|
||||
}
|
||||
.two-style {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
.break {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
73
components/diy/rich-text.vue
Normal file
73
components/diy/rich-text.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<!-- 富文本 -->
|
||||
<view class="diy-rich-text" :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<mp-html :content="content" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
content: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
this.setData({
|
||||
content: new_content.html,
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.diy-rich-text {
|
||||
* {
|
||||
max-width: 100%;
|
||||
}
|
||||
/* #ifdef H5 */
|
||||
[id^=v] {
|
||||
width: 100%;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
.diy-rich-text video {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
327
components/diy/search.vue
Normal file
327
components/diy/search.vue
Normal file
@@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="search wh-auto pr">
|
||||
<view class="box oh flex-row align-c" :style="box_style">
|
||||
<view v-if="form.positioning_name_float == '1' && propSearchType == 'header'" :style="propLocationMargin">
|
||||
<component-choice-location propType="search" :propLocationContainerStyle="propLocationContainerStyle" :propLocationImgContainerStyle="propLocationImgContainerStyle" :propBaseColor="propBaseColor" :propTextDefaultName="form.positioning_name" :propIsLeftIconArrow="form.is_location_left_icon_show == '1'" :propLeftImgValue="form.location_left_img" :propLeftIconValue="'icon-' + form.location_left_icon" :propIconLocationSize="propIconLocationSize" :propIconArrowSize="propIconArrowSize" :propIsRightIconArrow="form.is_location_right_icon_show == '1'" :propRightImgValue="form.location_right_img" :propRightIconValue="'icon-' + form.location_right_icon" :propTextMaxWidth="['4'].includes(form.theme) ? '300rpx' : '200rpx'" propContainerDisplay="flex" @onBack.stop="choice_location_back"></component-choice-location>
|
||||
</view>
|
||||
<view :class="'oh flex-1 ht-auto flex-row align-c gap-10' + (form.is_center == '1' ? ' tips-float' : '')" @tap.stop="search_tap">
|
||||
<view v-if="form.is_icon_show == '1'" class="pr">
|
||||
<view class="search-icon-before" :style="(form.positioning_name_float == '1' && propSearchType == 'header') || form.is_center == '1' ? '' : 'left: -' + (new_style.search_padding_left ? new_style.search_padding_left * 2 : 30) + 'rpx;'" @tap.stop="search_icon_tap"></view>
|
||||
<view class="wh-auto ht-auto">
|
||||
<template v-if="form.icon_img.length > 0">
|
||||
<view class="img-box">
|
||||
<image :src="form.icon_img[0].url" class="img" mode="heightFix"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view>
|
||||
<iconfont :name="!isEmpty(form.icon_class) ? 'icon-' + form.icon_class : 'icon-search-max'" size="28rpx" :color="new_style.icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!isEmpty(form.hot_word_list) && form.is_hot_word_show == '1'" :style="form.is_center == '1' ? `min-width:100px;` : 'width:100%;'">
|
||||
<swiper circular="true" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :vertical="true" :duration="500" class="swiper_style" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in form.hot_word_list" :key="index">
|
||||
<view class="flex-row align-c wh-auto ht-auto" :style="{ color: !isEmpty(item.color) ? item.color : !isEmpty(new_style.hot_words_color) ? new_style.hot_words_color : '#999' }" :data-value="item.value" @tap.stop="serch_event">
|
||||
{{ item.value }}
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
<template v-else>
|
||||
<text v-if="form.is_tips_show == '1'" :class="[propIsPageSettings ? 'text-size-xs text-line-1' : 'text-size-md text-line-1']" :style="'color:' + new_style.tips_color">{{ form.tips }}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row align-c pa search-outer-botton oh" :style="right_icon_style">
|
||||
<view v-if="form.is_right_icon_show == '1' && (form.right_icon_img.length > 0 || !isEmpty(form.right_icon_class))" class="pr margin-right-main">
|
||||
<view class="search-icon-before" @tap.stop="search_right_icon_tap"></view>
|
||||
<view class="wh-auto ht-auto">
|
||||
<template v-if="form.right_icon_img.length > 0">
|
||||
<view class="img-box right_icon_height flex-row align-c">
|
||||
<image :src="form.right_icon_img[0].url" class="img" mode="heightFix"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="right_icon_height flex-row align-c">
|
||||
<iconfont :name="!isEmpty(form.right_icon_class) ? 'icon-' + form.right_icon_class : 'icon-search-max'" size="28rpx" :color="new_style.right_icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="form.is_search_show == '1'" class="flex-row align-c jc-c">
|
||||
<view class="search-botton flex-row align-c jc-c z-i" :style="search_button_style" @tap.stop="serch_button_event">
|
||||
<view class="oh" :style="search_button_img_style">
|
||||
<template v-if="form.search_type === 'text'">
|
||||
<view class="text-size-xs">{{ form.search_tips }}</view>
|
||||
</template>
|
||||
<template v-else-if="!isEmpty(form.search_botton_img) && form.search_botton_img.length > 0">
|
||||
<image :src="form.search_botton_img[0].url" class="img" :style="search_button_height" mode="heightFix"></image>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="text-size-xs">
|
||||
<iconfont :name="!isEmpty(form.search_botton_icon) ? 'icon-' + form.search_botton_icon : ''" size="28rpx" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import componentChoiceLocation from '@/components/choice-location/choice-location';
|
||||
const app = getApp();
|
||||
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, radius_computer, isEmpty, padding_computer, old_padding, old_radius, margin_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
components: {
|
||||
componentChoiceLocation,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propIsPageSettings: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propSearchType: {
|
||||
type: String,
|
||||
default: 'search',
|
||||
},
|
||||
propBaseColor: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propLocationMargin: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propLocationContainerStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propLocationImgContainerStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIconLocationSize: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIconArrowSize: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search_content: '',
|
||||
form: {},
|
||||
new_style: {},
|
||||
style: '',
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
search_button_radius: '',
|
||||
box_style: '',
|
||||
keywords: '',
|
||||
right_icon_style: '',
|
||||
search_button_style: '',
|
||||
search_button_img_style: '',
|
||||
search_button_height: '',
|
||||
button_padding: { padding: 0, padding_bottom: 3, padding_left: 12, padding_right: 12, padding_top: 3 },
|
||||
button_margin: { margin: 0, margin_bottom: 2, margin_left: 0, margin_right: 2, margin_top: 2 },
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
const { search_button_radius, common_style } = new_style;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
search_button_img_style: this.get_search_button_img_style(new_style),
|
||||
search_button_height: this.get_search_button_height(new_style),
|
||||
// style: this.get_style(new_style), // 内部样式
|
||||
style_container: this.propIsPageSettings ? '' : common_styles_computer(common_style), // 全局样式
|
||||
style_img_container: this.propIsPageSettings ? '' : common_img_computer(common_style, this.propIndex),
|
||||
search_button_radius: radius_computer(search_button_radius), // 按钮圆角
|
||||
box_style: this.get_box_style(new_style, new_form), // 搜索框设置
|
||||
search_box_style: `border: 2rpx solid ${new_style.search_border == '#fff' ? '#eee' : new_style.search_border};`,
|
||||
search_button_style: this.get_search_button_style(new_form, new_style), // 搜索按钮显示
|
||||
right_icon_style: `border-radius: 0px ${ new_style.search_border_radius?.radius_top_right * 2 || 0 }rpx ${ new_style.search_border_radius?.radius_bottom_right * 2 || 0 }rpx 0px;`,
|
||||
});
|
||||
},
|
||||
get_search_button_style(form, new_style) {
|
||||
const { search_botton_color_list = [], search_botton_direction, search_botton_background_img_style, search_button_radius = old_radius, search_botton_background_img, search_botton_margin = this.button_margin, search_botton_border_show = '0', search_botton_border_size = old_padding, search_botton_border_style = 'solid', search_botton_border_color = '' } = new_style;
|
||||
let style = radius_computer(search_button_radius);
|
||||
if (form.search_type != 'img') {
|
||||
const data = {
|
||||
color_list: search_botton_color_list,
|
||||
direction: search_botton_direction,
|
||||
background_img: search_botton_background_img,
|
||||
background_img_style: search_botton_background_img_style,
|
||||
}
|
||||
style += gradient_computer(data) + margin_computer(search_botton_margin) + `color: ${ new_style.button_inner_color };`;
|
||||
}
|
||||
let border = ``;
|
||||
if (search_botton_border_show == '1') {
|
||||
border += `border-width: ${search_botton_border_size.padding_top * 2}rpx ${search_botton_border_size.padding_right * 2}rpx ${search_botton_border_size.padding_bottom * 2}rpx ${search_botton_border_size.padding_left * 2}rpx;border-style: ${ search_botton_border_style };border-color: ${search_botton_border_color};`
|
||||
}
|
||||
const height = 32 - search_botton_margin.margin_top - search_botton_margin.margin_bottom - search_botton_border_size.padding_top - search_botton_border_size.padding_bottom;
|
||||
return style + border + `height: ${height > 0 ? height * 2 : 0}rpx;line-height: ${height > 0 ? height * 2 : 0}rpx;`;
|
||||
},
|
||||
get_search_button_height(new_style) {
|
||||
const { search_botton_border_size = old_padding, search_botton_padding = this.button_padding } = new_style;
|
||||
const height = 32 - search_botton_border_size.padding_top - search_botton_border_size.padding_bottom - search_botton_padding.padding_top - search_botton_padding.padding_bottom;
|
||||
return `height: ${height > 0 ? height * 2 : 0}rpx !important;line-height: ${height > 0 ? height * 2 : 0}rpx;`;
|
||||
},
|
||||
// 搜索按钮圆角
|
||||
get_search_button_img_style(new_style) {
|
||||
const { search_botton_background_img_style, search_botton_background_img } = new_style;
|
||||
const data = {
|
||||
background_img: search_botton_background_img,
|
||||
background_img_style: search_botton_background_img_style,
|
||||
}
|
||||
return background_computer(data) + padding_computer(new_style?.search_botton_padding || this.button_padding) + 'box-sizing: border-box;';
|
||||
},
|
||||
// get_style(new_style) {
|
||||
// let common_styles = '';
|
||||
// if (new_style.text_style == 'italic') {
|
||||
// common_styles += `font-style: italic`;
|
||||
// } else if (new_style.text_style == '500') {
|
||||
// common_styles += `font-weight: 500`;
|
||||
// }
|
||||
// return common_styles;
|
||||
// },
|
||||
get_box_style(new_style, form) {
|
||||
let style = `background: ${ new_style?.search_bg_color || '' };border: 2rpx solid ${new_style.search_border}; ${radius_computer(new_style.search_border_radius)};box-sizing: border-box;`;
|
||||
if (form.positioning_name_float == '1' && this.propSearchType == 'header') {
|
||||
style += `padding-left: ${ (new_style.search_padding_left? new_style.search_padding_left : 15) * 2 }rpx;`;
|
||||
} else if (form.is_center != '1') {
|
||||
style += `padding-left: ${ (new_style.search_padding_left ? new_style.search_padding_left : 15) * 2 }rpx;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
search_tap() {
|
||||
app.globalData.url_open('/pages/goods-search-start/goods-search-start?keywords=' + this.keywords);
|
||||
},
|
||||
serch_event() {
|
||||
app.globalData.url_open('/pages/goods-search-start/goods-search-start?keywords=' + this.keywords);
|
||||
},
|
||||
serch_button_event() {
|
||||
if (!isEmpty(this.keywords)) {
|
||||
app.globalData.url_open('pages/goods-search/goods-search?keywords=' + this.keywords);
|
||||
}
|
||||
app.globalData.url_open('/pages/goods-search-start/goods-search-start?keywords=' + this.keywords);
|
||||
},
|
||||
search_icon_tap() {
|
||||
if (isEmpty(this.form.icon_link)) {
|
||||
this.search_tap();
|
||||
return;
|
||||
}
|
||||
app.globalData.url_open(this.form.icon_link.page);
|
||||
},
|
||||
search_right_icon_tap() {
|
||||
if (isEmpty(this.form.right_icon_link)) {
|
||||
this.search_tap();
|
||||
return;
|
||||
}
|
||||
app.globalData.url_open(this.form.right_icon_link.page);
|
||||
},
|
||||
slideChange(e) {
|
||||
let actived_index = e.detail.current;
|
||||
this.setData({
|
||||
keywords: this.form.hot_word_list[actived_index].value,
|
||||
})
|
||||
},
|
||||
// 位置回调
|
||||
onBack(e) {
|
||||
this.$emit('onBack', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search {
|
||||
.box {
|
||||
height: 64rpx;
|
||||
// padding: 12rpx 30rpx;
|
||||
}
|
||||
.swiper_style {
|
||||
height: 64rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.img-box {
|
||||
height: 100%;
|
||||
.img {
|
||||
height: 36rpx;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.search-outer-botton {
|
||||
height: 64rpx;
|
||||
top: 0;
|
||||
right: 0;
|
||||
.search-botton {
|
||||
height: 64rpx;
|
||||
.img {
|
||||
height: 64rpx;
|
||||
min-width: 6rpx;
|
||||
max-width: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right_icon_height {
|
||||
position: relative;
|
||||
height: 56rpx !important;
|
||||
}
|
||||
.search-icon {
|
||||
position: relative;
|
||||
}
|
||||
.search-icon-before {
|
||||
position: absolute;
|
||||
z-index: 10; // 确保悬浮在内容上层
|
||||
top: -20rpx;
|
||||
right: -20rpx;
|
||||
bottom: -20rpx;
|
||||
left: -20rpx
|
||||
}
|
||||
.tips-float {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
643
components/diy/seckill.vue
Normal file
643
components/diy/seckill.vue
Normal file
@@ -0,0 +1,643 @@
|
||||
<template>
|
||||
<view v-if="!isEmpty(list) || !isEmpty(sckill_list)" :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="flex-col gap-10">
|
||||
<view v-if="form.head_state == '1'" class="oh" :style="seckill_head_style">
|
||||
<view class="seckill-head flex-row align-c jc-sb" :style="seckill_head_img_style">
|
||||
<view :class="['flex-row align-c', { 'gap-10': form.theme != '1', 'jc-sb wh-auto': form.theme == '2' }]">
|
||||
<view class="seckill-title">
|
||||
<imageEmpty v-if="form.title_type == 'image'" :propImageSrc="form.title_src[0]" propImgFit="heightFix" propErrorStyle="width:42rpx; height: 20rpx;"></imageEmpty>
|
||||
<text v-else :style="{ color: new_style.title_color, 'font-size': new_style.title_size * 2 + 'rpx', 'line-height': '42rpx', 'font-weight': 600 }">{{ form.title_text }}</text>
|
||||
</view>
|
||||
<view v-if="form.theme == '1'" class="padding-horizontal-sm cr-white">|</view>
|
||||
<view v-if="intervalId != undefined" class="flex-row align-c gap-4">
|
||||
<text class="text-size-xss" :style="{ color: new_style.end_text_color }">{{ seckill_time.time_first_text }}</text>
|
||||
<view class="flex-row gap-3 jc-c align-c" :style="form.theme == '4' ? time_bg + 'padding: 6rpx 8rpx;border-radius: 22rpx;' : ''">
|
||||
<image v-if="form.theme == '4' && form.theme_4_static_img.length > 0" class="seckill-head-icon radius-xs" :src="form.theme_4_static_img[0].url" />
|
||||
<view v-for="(item, index) in time_config" :key="item.key" class="flex-row gap-3 jc-c align-c">
|
||||
<template v-if="form.theme == '4'">
|
||||
<view class="text-size-xs flex-row jc-c align-c" :style="'min-width:50rpx;color:' + new_style.countdown_color">{{ item.value }}</view>
|
||||
<text v-if="[0, 1].includes(index)" class="colon" :style="{ color: new_style.countdown_color }">:</text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="time-config text-size-xs flex-row jc-c align-c" :style="time_bg + 'min-width:50rpx;color:' + new_style.countdown_color">{{ item.value }}</view>
|
||||
<text v-if="[0, 1].includes(index)" class="colon" :style="icon_time_check">:</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="flex-row align-c gap-4">
|
||||
<text class="text-size-xss" :style="{ color: new_style.end_text_color }">已结束</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="form.button_status == '1'" class="flex-row align-c" :style="{ color: new_style.head_button_color }" :data-value="'/pages/plugins/seckill/index/index'" @tap="url_event">
|
||||
<text :style="{ 'font-size': new_style.head_button_size * 2 + 'rpx' }">{{ form.button_text }}</text>
|
||||
<iconfont name="icon-arrow-right" :color="new_style.head_button_color" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="oh" :style="shop_container">
|
||||
<view class="oh" :style="shop_img_container">
|
||||
<template v-if="form.shop_style_type != '3'">
|
||||
<view class="flex-row flex-wrap wh-auto ht-auto" :style="{ gap: content_outer_spacing }">
|
||||
<view v-for="(item, index) in sckill_list" :key="index" :style="layout_style + layout_type_style + content_radius" :data-value="item.goods_url" @tap="url_event">
|
||||
<view :class="layout_type" :style="layout_img_style">
|
||||
<template v-if="!isEmpty(item)">
|
||||
<view class="oh pr">
|
||||
<view v-if="!isEmpty(item.new_cover)" :style="img_size">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="content_img_radius" propErrorStyle="width:100rpx; height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-else :style="img_size">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="content_img_radius" propErrorStyle="width:100rpx; height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="is_show('title') || is_show('simple_desc') || is_show('price') || is_show('original_price') || form.is_shop_show == '1'" class="flex-col gap-10 wh-auto flex-1 jc-sb oh" :style="content_style">
|
||||
<view class="flex-col gap-10 wh-auto">
|
||||
<!-- 标题 -->
|
||||
<view v-if="is_show('title') || is_show('simple_desc')" class="flex-col" :style="{'gap': new_style.title_simple_desc_spacing * 2 + 'rpx' }">
|
||||
<view v-if="is_show('title')" :style="title_style" class="text-line-2">{{ item.title }}</view>
|
||||
<view v-if="is_show('simple_desc')" class="text-line-1" :style="simple_desc">{{ item.simple_desc }}</view>
|
||||
</view>
|
||||
<!-- 进度条 -->
|
||||
<!-- <view v-if="form.shop_style_type == '1'" class="flex-row align-c gap-6">
|
||||
<view class="re flex-1">
|
||||
<view class="slide-bottom" :style="`background: ${new_style.progress_bg_color}`"></view>
|
||||
<view class="slide-top" :style="` width: 51%; ${slide_active_color}`">
|
||||
<view class="slide-top-icon round" :style="`background: ${new_style.progress_button_color}`"><icon name="a-miaosha" :color="new_style.progress_button_icon_color" size="9"></icon></view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="text-size-xss" :style="`color: ${new_style.progress_text_color}`">已抢51%</text>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="flex-row align-e gap-10 jc-sb">
|
||||
<view class="flex-col gap-5">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="{ color: new_style.shop_price_color }">
|
||||
<text v-if="form.shop_style_type == '1'" class="text-size-xss pr-4">{{ form.seckill_pirce_title ? form.seckill_pirce_title : ''}}</text>
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="is_show('original_price') && !isEmpty(item.min_original_price)" class="size-11 flex" :style="original_price">
|
||||
<text class="original-price text-line-1 flex-1">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<template v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</template>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="form.is_shop_show == '1'">
|
||||
<template v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + 'color:' + new_style.shop_button_text_color">{{ form.shop_button_text }}</view>
|
||||
</template>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :styles="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<swiper circular="false" :autoplay="new_style.is_roll == '1'" :next-margin="new_style.rolling_fashion == 'translation' ? '-' + content_outer_spacing_magin : '0rpx'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_group" :style="{ height: new_style.content_outer_height * 2 + 'rpx' }">
|
||||
<swiper-item v-for="(item1, index1) in list" :key="index1">
|
||||
<view class="wh-auto ht-auto" :class="{ 'flex-row': new_style.rolling_fashion != 'translation' }" :style="new_style.rolling_fashion != 'translation' ? 'gap:' + content_outer_spacing_magin : ''">
|
||||
<view v-for="(item, index) in item1.split_list" :key="index" :style="layout_style + content_radius + (new_style.rolling_fashion != 'translation' ? layout_type_style : 'margin-right:' + content_outer_spacing_magin + ';height: 100%;whith: 100%')" :data-value="item.goods_url" @tap="url_event">
|
||||
<view :class="layout_type" :style="layout_img_style">
|
||||
<template v-if="!isEmpty(item)">
|
||||
<view class="oh pr wh-auto ht-auto">
|
||||
<view v-if="!isEmpty(item.new_cover)" class="wh-auto ht-auto">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="content_img_radius" propErrorStyle="width:100rpx; height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-else class="wh-auto ht-auto">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="content_img_radius" propErrorStyle="width:100rpx; height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="is_show('title') || is_show('simple_desc') || is_show('price') || is_show('original_price') || form.is_shop_show == '1'" class="flex-col gap-10 wh-auto flex-1 jc-sb" :style="content_style">
|
||||
<view class="flex-col gap-10 wh-auto">
|
||||
<!-- 标题 -->
|
||||
<view v-if="is_show('title') || is_show('simple_desc')" class="flex-col" :style="{'gap': new_style.title_simple_desc_spacing * 2 + 'rpx' }">
|
||||
<view v-if="is_show('title')" :style="title_style" class="text-line-2">{{ item.title }}</view>
|
||||
<view v-if="is_show('simple_desc')" class="text-line-1" :style="simple_desc">{{ item.simple_desc }}</view>
|
||||
</view>
|
||||
<!-- 进度条 -->
|
||||
<!-- <view v-if="form.shop_style_type == '1'" class="flex-row align-c gap-6">
|
||||
<view class="re flex-1">
|
||||
<view class="slide-bottom" :style="{ 'background': new_style.progress_bg_color }"></view>
|
||||
<view class="slide-top" :style="'width: 51%;' + slide_active_color ">
|
||||
<view class="slide-top-icon round" :style="{ 'background': new_style.progress_button_color}"><icon name="a-miaosha" :color="new_style.progress_button_icon_color" size="9"></icon></view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="text-size-xss" :style="{ 'color': new_style.progress_text_color }">已抢51%</text>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="flex-row align-e gap-10 jc-sb">
|
||||
<view class="flex-col gap-5">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="{ color: new_style.shop_price_color }">
|
||||
<text v-if="form.shop_style_type == '1'" class="text-size-xss pr-4">{{ form.seckill_pirce_title ? form.seckill_pirce_title : ''}}</text>
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="is_show('original_price') && !isEmpty(item.min_original_price)" class="size-11 flex" :style="original_price">
|
||||
<text class="original-price text-line-1 flex-1">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<template v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</template>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="form.is_shop_show == '1'">
|
||||
<template v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + 'color:' + new_style.shop_button_text_color">{{ form.shop_button_text }}</view>
|
||||
</template>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :styles="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, gradient_handle, padding_computer, radius_computer, isEmpty, margin_computer, box_shadow_computer, border_computer, old_margin, old_border_and_box_shadow } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import subscriptIndex from '@/components/diy/modules/subscript/index.vue';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
subscriptIndex
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
time_bg: '',
|
||||
slide_active_color: '',
|
||||
seckill_head_style: '',
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
time_config: [
|
||||
{ key: 'hour', value: '00' },
|
||||
{ key: 'minute', value: '00' },
|
||||
{ key: 'second', value: '00' },
|
||||
],
|
||||
seckill_time: {},
|
||||
// 商品间距
|
||||
content_outer_spacing: '',
|
||||
content_outer_spacing_magin: '',
|
||||
// 圆角设置
|
||||
content_radius: '',
|
||||
// 内边距设置
|
||||
content_padding: '',
|
||||
// 内容区域的样式
|
||||
content_style: '',
|
||||
// 不同风格下的样式
|
||||
img_size: '',
|
||||
layout_type: '',
|
||||
layout_type_style: '',
|
||||
layout_img_style: '',
|
||||
layout_style: '',
|
||||
//图片圆角设置
|
||||
content_img_radius: '',
|
||||
//角标设置
|
||||
corner_marker: '',
|
||||
// 定时器
|
||||
intervalId: null,
|
||||
// 数据存储
|
||||
list: [],
|
||||
// 一屏显示的数量
|
||||
slides_per_group: '',
|
||||
// 内容样式
|
||||
title_style: '',
|
||||
price_style: '',
|
||||
button_style: '',
|
||||
simple_desc: '',
|
||||
price_symbol: '',
|
||||
price_unit: '',
|
||||
original_price: '',
|
||||
shop_container: '',
|
||||
shop_img_container: '',
|
||||
// 商品列表
|
||||
sckill_list: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
icon_time_check() {
|
||||
return `${this.time_bg};line-height: 1;background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;`;
|
||||
},
|
||||
// 按钮渐变色处理
|
||||
button_gradient() {
|
||||
return gradient_handle(this.new_style.shop_button_color, '180deg');
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 如果有定时任务执行,在离开的时候清空掉定时任务
|
||||
if (!isEmpty(this.intervalId)) {
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
const data = new_form.data;
|
||||
let new_list = [];
|
||||
if (data && !isEmpty(data.current)) {
|
||||
if (!isEmpty(data.current.goods)) {
|
||||
new_list = data.current.goods;
|
||||
}
|
||||
const { status, time_first_text } = data.current.time;
|
||||
this.setData({
|
||||
seckill_time: {
|
||||
time_end_number: Number(data.current.time_end_number + '000'),
|
||||
time_start_number: Number(data.current.time_start_number + '000'),
|
||||
status: status,
|
||||
time_first_text: time_first_text,
|
||||
},
|
||||
});
|
||||
// 先执行一次倒计时,后续的等待倒计时执行
|
||||
setTimeout(() => {
|
||||
this.updateCountdown();
|
||||
}, 0);
|
||||
this.setData({
|
||||
intervalId: setInterval(this.updateCountdown, 1000),
|
||||
});
|
||||
}
|
||||
// 默认数据
|
||||
const product_style_list = [
|
||||
{ name: '单列', value: '1', width: 110, height: 120 },
|
||||
{ name: '双列', value: '2', width: 180, height: 180 },
|
||||
{ name: '横向滑动', value: '3', width: 0, height: 0 },
|
||||
];
|
||||
const scale = sys_width / 390;
|
||||
let img_style = ``;
|
||||
if (['1'].includes(new_form.shop_style_type)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_width == 'number') {
|
||||
img_style += `width: ${ new_style.content_img_width * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_form.shop_style_type);
|
||||
if (list.length > 0) {
|
||||
img_style += `width: ${ list[0].width * scale }px;`;
|
||||
} else {
|
||||
img_style += 'width: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!['3'].includes(new_form.shop_style_type)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_height == 'number') {
|
||||
img_style += `height: ${ new_style.content_img_height * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_form.shop_style_type);
|
||||
if (list.length > 0) {
|
||||
img_style += `height: ${ list[0].height * scale }px;`;
|
||||
} else {
|
||||
img_style += 'height: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
const shop_style = new_style?.shop_style || old_border_and_box_shadow;
|
||||
this.setData({
|
||||
form: this.propValue.content,
|
||||
new_style: this.propValue.style,
|
||||
time_bg: this.get_time_bg(new_style),
|
||||
slide_active_color: this.get_slide_active_color(new_style),
|
||||
seckill_head_style: this.get_seckill_head_style(new_style, '1'),
|
||||
seckill_head_img_style: this.get_seckill_head_style(new_style, '2'),
|
||||
style_container: common_styles_computer(new_style.common_style) + 'box-sizing: border-box;',
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
content_outer_spacing: new_style.content_outer_spacing + 'px',
|
||||
content_outer_spacing_magin: new_style.content_outer_spacing * 2 + 'rpx',
|
||||
content_radius: radius_computer(new_style.shop_radius),
|
||||
content_padding: padding_computer(new_style.shop_padding) + 'box-sizing: border-box;',
|
||||
content_style: this.get_content_style(new_style, new_form),
|
||||
layout_type: new_form.shop_style_type == '1' ? 'flex-row wh-auto ht-auto oh' : 'flex-col wh-auto ht-auto oh',
|
||||
layout_img_style: this.get_layout_img_style(new_style, new_form),
|
||||
layout_type_style: this.get_layout_type_style(new_style, new_form),
|
||||
layout_style: gradient_handle(new_style.shop_color_list, new_style.shop_direction) + margin_computer(new_style?.shop_margin || old_margin) + border_computer(shop_style) + box_shadow_computer(shop_style),
|
||||
content_img_radius: radius_computer(new_style.shop_img_radius),
|
||||
corner_marker: this.get_corner_marker(new_style),
|
||||
slides_per_group: new_style.rolling_fashion == 'translation' ? new_form.carousel_col : 1,
|
||||
// 内容样式设置
|
||||
title_style: this.trends_config(new_style, 'title', 'title'),
|
||||
price_style: this.trends_config(new_style, 'price'),
|
||||
button_style: this.trends_config(new_style, 'button', 'gradient'),
|
||||
simple_desc: this.trends_config(new_style, 'simple_desc', 'desc'),
|
||||
price_symbol: !isEmpty(new_style.shop_price_symbol_color) ? this.trends_config(new_style, 'price_symbol') : 'font-size: 18rpx;color: #EA3323;' ,
|
||||
price_unit: !isEmpty(new_style.shop_price_unit_color) ? this.trends_config(new_style, 'price_unit') : 'font-size: 18rpx;color: #EA3323;',
|
||||
original_price: this.trends_config(new_style, 'original_price'),
|
||||
list: this.get_shop_content_list(new_list, new_form, new_style),
|
||||
shop_container: this.get_shop_container(new_style),
|
||||
shop_img_container: this.get_shop_img_container(new_style),
|
||||
sckill_list: new_list,
|
||||
img_size: img_style,
|
||||
});
|
||||
},
|
||||
// 商品内容区域显示
|
||||
get_shop_container(new_style){
|
||||
const { shop_content_color_list = [], shop_content_direction = '', shop_content_radius = old_radius, shop_content_margin = old_margin, shop_content = old_border_and_box_shadow } = new_style;
|
||||
// 渐变
|
||||
const gradient = { color_list: shop_content_color_list, direction: shop_content_direction };
|
||||
return gradient_computer(gradient) + radius_computer(shop_content_radius) + margin_computer(shop_content_margin) + border_computer(shop_content) + box_shadow_computer(shop_content);
|
||||
},
|
||||
get_shop_img_container (new_style) {
|
||||
const { shop_content_background_img_style = '2', shop_content_background_img = [], shop_content_padding = old_padding } = new_style;
|
||||
// 背景图
|
||||
const back = { background_img: shop_content_background_img, background_img_style: shop_content_background_img_style };
|
||||
return padding_computer(shop_content_padding) + background_computer(back);
|
||||
},
|
||||
get_shop_content_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
get_time_bg(new_style) {
|
||||
const { countdown_bg_color_list, countdown_direction } = new_style;
|
||||
// 渐变
|
||||
const gradient = { color_list: countdown_bg_color_list, direction: countdown_direction };
|
||||
return gradient_computer(gradient);
|
||||
},
|
||||
get_slide_active_color(new_style) {
|
||||
const { progress_actived_color_list, progress_actived_direction } = new_style;
|
||||
// 渐变
|
||||
const gradient = { color_list: progress_actived_color_list, direction: progress_actived_direction };
|
||||
return gradient_computer(gradient);
|
||||
},
|
||||
get_seckill_head_style(new_style, num) {
|
||||
const { header_background_img, header_background_img_style, header_background_color_list, header_background_direction, seckill_head_padding, seckill_head_radius, seckill_head_margin = old_margin, seckill_head_style = old_border_and_box_shadow } = new_style;
|
||||
// 渐变
|
||||
const gradient = { color_list: header_background_color_list, direction: header_background_direction };
|
||||
// 背景图
|
||||
const back = { background_img: header_background_img, background_img_style: header_background_img_style };
|
||||
if (num == '1') {
|
||||
return gradient_computer(gradient) + radius_computer(seckill_head_radius) + margin_computer(seckill_head_margin) + border_computer(seckill_head_style) + box_shadow_computer(seckill_head_style);
|
||||
} else {
|
||||
// 秒杀头部内间距设置, 没有的时候默认15px
|
||||
const padding = !isEmpty(seckill_head_padding) ? seckill_head_padding : { padding: 0, padding_top: 15, padding_bottom: 15, padding_left: 13, padding_right: 13};
|
||||
return background_computer(back) + padding_computer(padding) + 'box-sizing: border-box;';
|
||||
}
|
||||
},
|
||||
updateCountdown() {
|
||||
let time_end_number = this.seckill_time.time_end_number;
|
||||
if (this.seckill_time.status === 0) {
|
||||
time_end_number = this.seckill_time.time_start_number;
|
||||
}
|
||||
// 先获取秒杀结束时间和当前时间的差值
|
||||
const distance = time_end_number - new Date().getTime();
|
||||
// 如果倒计时结束,显示结束信息
|
||||
if (distance <= 1000) {
|
||||
clearInterval(this.intervalId);
|
||||
// 如果是待开始状态,则显示开始倒计时,并且在结束的时候根据结束时候再执行一个定时器
|
||||
if (this.seckill_time.status === 0) {
|
||||
this.setData({
|
||||
seckill_time: {
|
||||
time_end_number: this.seckill_time.time_end_number,
|
||||
time_start_number: this.seckill_time.time_start_number,
|
||||
status: 1,
|
||||
time_first_text: '距结束',
|
||||
},
|
||||
});
|
||||
// 先执行一次倒计时,后续的等待倒计时执行
|
||||
setTimeout(() => {
|
||||
this.updateCountdown();
|
||||
}, 0);
|
||||
this.setData({
|
||||
intervalId: setInterval(this.updateCountdown, 1000),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 计算时间
|
||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
this.time_config.forEach((item) => {
|
||||
if (item.key == 'hour') {
|
||||
item.value = hours < 10 ? '0' + hours : hours.toString();
|
||||
} else if (item.key == 'minute') {
|
||||
item.value = minutes < 10 ? '0' + minutes : minutes.toString();
|
||||
} else if (item.key == 'second') {
|
||||
item.value = seconds < 10 ? '0' + seconds : seconds.toString();
|
||||
}
|
||||
});
|
||||
},
|
||||
get_content_style(new_style, form) {
|
||||
const spacing_value = new_style.content_spacing;
|
||||
let spacing = '';
|
||||
if (form.shop_style_type == '1') {
|
||||
spacing = `margin-left: ${spacing_value * 2}rpx;`;
|
||||
} else {
|
||||
spacing = padding_computer(new_style.shop_padding) + 'box-sizing: border-box;';
|
||||
}
|
||||
return `${spacing}`;
|
||||
},
|
||||
get_layout_type_style(new_style, form) {
|
||||
return ['1', '2'].includes(form.shop_style_type) ? `height: 100%;width: ${this.get_multicolumn_columns_width(new_style, form)};min-width: ${this.get_multicolumn_columns_width(new_style, form)};` : `height: ${new_style.content_outer_height * 2}rpx;width: ${this.get_multicolumn_columns_width(new_style, form)};min-width: ${this.get_multicolumn_columns_width(new_style, form)};`;
|
||||
},
|
||||
get_layout_img_style(new_style, form) {
|
||||
const padding = ['1'].includes(form.shop_style_type) ? padding_computer(new_style.shop_padding) + 'box-sizing: border-box;' : '';
|
||||
const data = {
|
||||
background_img_style: new_style.shop_background_img_style,
|
||||
background_img: new_style.shop_background_img,
|
||||
}
|
||||
return `${padding} ${ background_computer(data) }`;
|
||||
},
|
||||
// 根据传递的参数,从对象中取值
|
||||
trends_config(new_style, key, type) {
|
||||
return this.style_config(new_style[`shop_${key}_typeface`], new_style[`shop_${key}_size`], new_style[`shop_${key}_color`], type, new_style);
|
||||
},
|
||||
// 根据传递的值,显示不同的内容
|
||||
style_config(typeface, size, color, type, new_style) {
|
||||
let style = `font-weight:${typeface}; font-size: ${size * 2}rpx;`;
|
||||
if (type == 'gradient') {
|
||||
style += gradient_handle(new_style.shop_button_color, '180deg');
|
||||
} else if (type == 'title') {
|
||||
style += `line-height: ${size > 0 ? (size + 3) * 2 : 0}rpx;height: ${size > 0 ? (size + 3) * 4 : 0}rpx;color: ${color};`;
|
||||
} else if (type == 'desc') {
|
||||
style += `line-height: ${size * 2}rpx;height: ${size * 2}rpx;color: ${color};`;
|
||||
} else {
|
||||
style += `color: ${color};`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
get_multicolumn_columns_width(new_style, form) {
|
||||
let model_number = form.carousel_col;
|
||||
if (form.shop_style_type == '1') {
|
||||
model_number = 1;
|
||||
} else if (form.shop_style_type == '2') {
|
||||
model_number = 2;
|
||||
}
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.content_outer_spacing * (model_number - 1)) / model_number;
|
||||
return `calc(${100 / model_number}% - ${gap}px)`;
|
||||
},
|
||||
is_show(index) {
|
||||
return this.form.is_show.includes(index);
|
||||
},
|
||||
get_corner_marker(new_style) {
|
||||
const { seckill_subscript_location, shop_img_radius, seckill_subscript_bg_color, seckill_subscript_text_color } = new_style;
|
||||
let location = `background: ${seckill_subscript_bg_color};color: ${seckill_subscript_text_color};`;
|
||||
// 圆角根据图片的圆角来计算 对角线是同样的圆角
|
||||
if (seckill_subscript_location == 'top-left') {
|
||||
location += `top: 0;left: 0;border-radius: ${shop_img_radius.radius_top_left * 2}rpx 0 ${shop_img_radius.radius_top_left * 2}rpx 0;`;
|
||||
} else if (seckill_subscript_location == 'top-right') {
|
||||
location += `top: 0;right: 0;border-radius: 0 ${shop_img_radius.radius_top_right * 2}rpx 0 ${shop_img_radius.radius_top_right * 2}rpx;`;
|
||||
} else if (seckill_subscript_location == 'bottom-left') {
|
||||
location += `bottom: 0;left: 0;border-radius: 0 ${shop_img_radius.radius_bottom_left * 2}rpx 0 ${shop_img_radius.radius_bottom_left * 2}rpx;`;
|
||||
} else if (seckill_subscript_location == 'bottom-right') {
|
||||
location += `bottom: 0;right: 0;border-radius: ${shop_img_radius.radius_bottom_right * 2}rpx 0 ${shop_img_radius.radius_bottom_right * 2}rpx 0;`;
|
||||
}
|
||||
return location;
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(link) {
|
||||
app.globalData.url_event(link);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.seckill-head {
|
||||
padding: 30rpx 26rpx;
|
||||
width: 100%;
|
||||
height: 102rpx;
|
||||
border-radius: 16rpx 16rpx 0 0;
|
||||
box-sizing: border-box;
|
||||
.seckill-title {
|
||||
width: auto;
|
||||
height: 42rpx;
|
||||
}
|
||||
.time-config {
|
||||
padding: 2rpx 10rpx;
|
||||
box-sizing: border-box;
|
||||
line-height: 34rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
.seckill-head-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
.colon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 33rpx;
|
||||
top: -2rpx;
|
||||
}
|
||||
.slide-bottom {
|
||||
height: 20rpx;
|
||||
border-radius: 10rpx;
|
||||
background: red;
|
||||
}
|
||||
.slide-top {
|
||||
position: absolute;
|
||||
height: 20rpx;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-radius: 10rpx;
|
||||
.slide-top-icon {
|
||||
position: absolute;
|
||||
top: -6rpx;
|
||||
right: 0;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
.original-price {
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
.size-11 {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
</style>
|
||||
231
components/diy/tabs-carousel.vue
Normal file
231
components/diy/tabs-carousel.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<view class="ou pr" :style="style_container + swiper_bg_style">
|
||||
<view class="pa top-0 wh-auto ht-auto" :style="swiper_bg_img_style"></view>
|
||||
<view class="ou wh-auto" :style="style_img_container + (!isEmpty(swiper_bg_img_style) ? swiper_bg_img_style_null : '')">
|
||||
<componentDiyTabs :propKey="propKey" :propContentPadding="propContentPadding" :propValue="propValue" :propTop="propTop" :propIsRotatingBackground="is_rotating_background" :propBgStyle="swiper_bg_style" :propBgImgStyle="swiper_bg_img_style" :propStickyTop="propStickyTop" :propIsImmersionModel="propIsImmersionModel" :propNewIsTabsSafeDistance="new_is_tabs_safe_distance" :propNavIsTop="propNavIsTop" :propTabsIsTop="propTabsIsTop" :propIsCommon="false" :propsTabsContainer="tabs_container" :propsTabsImgContainer="tabs_img_container" :propSpacingCommonStyle="spacing_common_style" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" @onComputerHeight="tabs_height_event" @onTabsTap="tabs_click_event"></componentDiyTabs>
|
||||
<view :style="carousel_margin_top">
|
||||
<view :style="carousel_container">
|
||||
<view :style="carousel_img_container">
|
||||
<componentDiycarousel :propValue="propValue" :propIsCommon="false" @onVideoPlay="video_play" @slideChange="slideChange"></componentDiycarousel>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, isEmpty, gradient_computer, margin_computer, background_computer, radius_computer, old_margin, old_padding, old_radius, old_border_and_box_shadow, border_computer, box_shadow_computer, } from '@/common/js/common/common.js';
|
||||
import componentDiyTabs from '@/components/diy/tabs';
|
||||
import componentDiycarousel from '@/components/diy/carousel';
|
||||
export default {
|
||||
components: {
|
||||
componentDiyTabs,
|
||||
componentDiycarousel,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propTop: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
propStickyTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 是否导航栏置顶
|
||||
propNavIsTop: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否选项卡置顶
|
||||
propTabsIsTop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propContentPadding: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
// 选项卡是否使用安全距离
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style_margin_container: '',
|
||||
spacing_common_style: {
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
},
|
||||
tabs_padding_style: '',
|
||||
// 选项卡内容
|
||||
tabs_container: '',
|
||||
tabs_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
// 轮播图内容
|
||||
carousel_margin_top: '',
|
||||
carousel_container: '',
|
||||
carousel_img_container: '',
|
||||
// top_up: '0',
|
||||
actived_index: 0,
|
||||
// 轮播图背景
|
||||
swiper_bg_style: '',
|
||||
swiper_bg_img_style: '',
|
||||
swiper_bg_img_style_null: `background-image: url('')`,
|
||||
is_rotating_background: false,
|
||||
new_is_tabs_safe_distance: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propTabsIsTop(value, old_value) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
const { tabs_bg_color_list = [], tabs_bg_direction = '', tabs_bg_background_img_style = '', tabs_bg_background_img = [], tabs_radius = old_radius, tabs_padding = old_padding, tabs_margin = old_margin, tabs_content = old_border_and_box_shadow, carousel_content_color_list = [], carousel_content_direction = '', carousel_content_background_img_style = '', carousel_content_background_img = [], carousel_content_margin = old_margin, carousel_content_padding = old_padding, carousel_content_radius = old_radius, carousel_content = old_border_and_box_shadow } = new_style;
|
||||
// 选项卡背景设置
|
||||
const tabs_data = {
|
||||
color_list: tabs_bg_color_list,
|
||||
direction: tabs_bg_direction,
|
||||
background_img_style: tabs_bg_background_img_style,
|
||||
background_img: tabs_bg_background_img,
|
||||
}
|
||||
// 商品区域背景设置
|
||||
const carousel_content_data = {
|
||||
color_list: carousel_content_color_list,
|
||||
direction: carousel_content_direction,
|
||||
background_img_style: carousel_content_background_img_style,
|
||||
background_img: carousel_content_background_img,
|
||||
}
|
||||
// 头部的高度
|
||||
const newPropTop = app.globalData.rpx_to_px(this.propTop);
|
||||
// 选项卡的外边距
|
||||
const new_tabs_top = app.globalData.rpx_to_px(tabs_margin?.margin_top || 0);
|
||||
// 选项卡的实际外边距
|
||||
const tabs_margin_top = new_content.is_tabs_safe_distance == '1' ? newPropTop + this.propStickyTop : 0;
|
||||
// 选项卡的内边距处理
|
||||
const new_padding_top = new_style.common_style.padding_top - newPropTop;
|
||||
this.setData({
|
||||
// style_container: `${common_styles_computer(common_style)};gap:${new_style.data_spacing * 2}rpx`,
|
||||
style_container: `${common_styles_computer(new_style.common_style)};`,
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
carousel_margin_top: 'margin-top:' + new_style.data_spacing * 2 + 'rpx',
|
||||
new_is_tabs_safe_distance: new_content.is_tabs_safe_distance == '1',
|
||||
// 是否开启轮播图背景设置
|
||||
is_rotating_background: new_content.rotating_background == '1',
|
||||
tabs_sliding_fixed_bg: gradient_computer(tabs_data),
|
||||
tabs_container: gradient_computer(tabs_data) + radius_computer(tabs_radius) + margin_computer(tabs_margin) + border_computer(tabs_content) + box_shadow_computer(tabs_content) + `overflow: hidden;margin-top: ${ new_tabs_top - tabs_margin_top }px;`,
|
||||
tabs_img_container: background_computer(tabs_data) + padding_computer(tabs_padding) + `box-sizing: border-box;overflow: hidden;padding-top: ${ (tabs_padding?.padding_top || 0) + tabs_margin_top }px;`,
|
||||
carousel_container: gradient_computer(carousel_content_data) + margin_computer(carousel_content_margin) + radius_computer(carousel_content_radius) + border_computer(carousel_content) + box_shadow_computer(carousel_content) + 'overflow: hidden;',
|
||||
carousel_img_container: background_computer(carousel_content_data) + padding_computer(carousel_content_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
spacing_common_style: {
|
||||
padding: 0,
|
||||
padding_top: (this.propIsImmersionModel && new_content.is_tabs_safe_distance == '1' ? new_style.common_style.padding_top + this.propStickyTop : new_padding_top > 0 ? new_padding_top : 0),
|
||||
padding_bottom: 0,
|
||||
padding_left: new_style.common_style.padding_left,
|
||||
padding_right: new_style.common_style.padding_right,
|
||||
margin: 0,
|
||||
margin_top: new_style.common_style.margin_top,
|
||||
margin_left: new_style.common_style.margin_left,
|
||||
margin_right: new_style.common_style.margin_right,
|
||||
},
|
||||
swiper_bg_style: this.get_swiper_bg_style(new_content, 0),
|
||||
swiper_bg_img_style: this.get_swiper_bg_img_style(new_content, 0),
|
||||
});
|
||||
},
|
||||
// tab点击
|
||||
tabs_click_event(tabs_id, is_micro_page) {
|
||||
this.$emit('onTabsTap', tabs_id, is_micro_page);
|
||||
},
|
||||
// tab高度
|
||||
tabs_height_event(height) {
|
||||
this.$emit('onComputerHeight', height);
|
||||
},
|
||||
// 视频播放
|
||||
video_play(url, popup_width, popup_height) {
|
||||
this.$emit('onVideoPlay', url, popup_width, popup_height);
|
||||
},
|
||||
get_swiper_bg_style(form, actived_index) {
|
||||
const style = form?.carousel_list?.[actived_index]?.style;
|
||||
if (style && !isEmpty(style.color_list)) {
|
||||
const color_list = style.color_list;
|
||||
const list = color_list.filter((item) => !isEmpty(item.color));
|
||||
if (list.length > 0) {
|
||||
try {
|
||||
return gradient_computer(style);
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
get_swiper_bg_img_style(form, actived_index) {
|
||||
const { carousel_img, style = {} } = form?.carousel_list[actived_index] || {};
|
||||
// 如果是自定义的图片 判断图片是否存在
|
||||
if (!isEmpty(carousel_img) && style?.background_type == 'carousel') {
|
||||
// 如果是使用轮播图,判断轮播图是否存在
|
||||
const data = {
|
||||
background_img: carousel_img,
|
||||
background_img_style: style?.background_img_style || '2',
|
||||
}
|
||||
return background_computer(data) + (style.is_background_img_blur == '1' ? `filter: blur(14px);opacity: 0.6;` : '');
|
||||
} else if (!isEmpty(style?.background_img)) {
|
||||
return background_computer(style) + (style.is_background_img_blur == '1' ? `filter: blur(14px);opacity: 0.6;` : '');
|
||||
}
|
||||
return '';
|
||||
},
|
||||
slideChange(index) {
|
||||
this.setData({
|
||||
actived_index: index,
|
||||
swiper_bg_style: this.get_swiper_bg_style(this.propValue.content || {}, index),
|
||||
swiper_bg_img_style: this.get_swiper_bg_img_style(this.propValue.content || {}, index),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
270
components/diy/tabs.vue
Normal file
270
components/diy/tabs.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<!-- 选项卡 -->
|
||||
<view class="tabs-container pr" :style="tabs_z_index">
|
||||
<view :class="top_up == '1' ? 'tabs-top' : ''" :style="tabs_top_style + (top_up == '1' ? propContentPadding : '')">
|
||||
<view :style="style_margin_container">
|
||||
<view class="tabs-contents bs-bb pr" :style="style_container">
|
||||
<view :class="top_up == '1' ? 'bs-bb' : 'wh-auto bs-bb'" :style="style_img_container">
|
||||
<componentDiyModulesTabsView :propKey="propKey" :propValue="tabs_data" :propIsTabsIcon="true" :propTop="propTop" :propsTabsContainer="propsTabsContainer + (propIsRotatingBackground ? propBgStyle : '')" :propIsRotatingBackground="propIsRotatingBackground" :propBgImgStyle="propBgImgStyle" :propsTabsImgContainer="propsTabsImgContainer" :propStyle="propStyle" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" @onTabsTap="tabs_click_event" @tabsZindex="tabsZindex"></componentDiyModulesTabsView>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="top_up == '1'" class="tabs-seat" :style="'height:' + (propIsCommon ? tabs_seat_height : tabs_carousel_seat_height) + 'px;'"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, margin_computer, gradient_computer, background_computer } from '@/common/js/common/common.js';
|
||||
import componentDiyModulesTabsView from '@/components/diy/modules/tabs-view';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
// 置顶距离顶部高度
|
||||
propTop: {
|
||||
type: [String, Number],
|
||||
default: '0',
|
||||
},
|
||||
propStickyTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 是否导航栏置顶
|
||||
propNavIsTop: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否选项卡置顶
|
||||
propTabsIsTop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsCommon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propSpacingCommonStyle: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
// 样式
|
||||
propStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propsTabsContainer: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propsTabsImgContainer: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propContentPadding: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propNewIsTabsSafeDistance: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
propTabsSlidingFixedBg: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propIsRotatingBackground: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propBgStyle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propBgImgStyle: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
componentDiyModulesTabsView,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
content: '',
|
||||
tabs_data: {},
|
||||
// 是否滑动置顶
|
||||
top_up: '0',
|
||||
// 置顶时,选项卡高度
|
||||
tabs_seat_height: 0,
|
||||
// 置顶时,轮播选项卡高度
|
||||
tabs_carousel_seat_height: 0,
|
||||
// 置顶时,选项卡样式
|
||||
tabs_top_style: '',
|
||||
style_margin_container: '',
|
||||
tabs_z_index: ''
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
this.get_tabs_height();
|
||||
}, 100);
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propTabsIsTop(value, old_value) {
|
||||
this.init();
|
||||
setTimeout(() => {
|
||||
this.get_tabs_height();
|
||||
}, 100);
|
||||
},
|
||||
propTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propStickyTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
propSpacingCommonStyle(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
let new_tabs_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
new_tabs_data.content.tabs_list.unshift(new_tabs_data.content.home_data);
|
||||
// 判断选项卡是否置顶
|
||||
let other_style = this.propTop;
|
||||
let new_tabs_top_style = this.propNavIsTop || this.propTabsIsTop || new_content.tabs_top_up == '1' ? (new_content.tabs_top_up == '1' ? 'top:calc(' + (this.propStickyTop > 0 ? this.propStickyTop + 'px + ' : '') + other_style * 2 + 'rpx);z-index:11;' : '') : '';
|
||||
let new_top_up = new_content.tabs_top_up;
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// if (this.propTabsIsTop) {
|
||||
// other_style = '0';
|
||||
// }
|
||||
new_tabs_top_style = 'top:calc(' + (this.propStickyTop > 0 ? this.propStickyTop + 'px + ' : '') + other_style * 2 + 'rpx);z-index:11;';
|
||||
new_top_up = this.propNavIsTop || this.propTabsIsTop ? new_content.tabs_top_up : '0';
|
||||
// #endif
|
||||
let tabs_bg = new_style.common_style.color_list;
|
||||
let new_tabs_background = '';
|
||||
if (!Array.isArray(tabs_bg) || tabs_bg.length === 0 || !tabs_bg[0] || !tabs_bg[0].color) {
|
||||
new_tabs_background = 'background:#fff;';
|
||||
}
|
||||
const newPropTop = this.propIsCommon ? (app.globalData.rpx_to_px(this.propTop) + this.propStickyTop) : (app.globalData.rpx_to_px(this.propTop + this.propStickyTop));
|
||||
this.setData({
|
||||
tabs_data: new_tabs_data,
|
||||
tabs_sliding_fixed_bg: this.propIsCommon ? gradient_computer(new_style.common_style) : this.propTabsSlidingFixedBg,
|
||||
style_container: this.propIsCommon ? new_tabs_background + common_styles_computer(new_style.common_style) : new_content.tabs_top_up == '1' ? new_tabs_background + gradient_computer(new_style.common_style) + margin_computer(this.propSpacingCommonStyle) : '', // 如果是选项卡轮播,不需要走默认样式
|
||||
// 如果开了滑动置顶,并且开了沉浸式,不需要走传递过来的index,否则的话就用传递过来的index
|
||||
style_img_container: this.propIsCommon ? common_img_computer(new_style.common_style, this.propIndex) : new_content.tabs_top_up == '1' ? background_computer(new_style.common_style) + padding_computer(this.propSpacingCommonStyle, 1, false) + 'box-sizing: border-box;' : '', // 如果是选项卡轮播,不需要走默认样式
|
||||
tabs_top_style: new_tabs_top_style,
|
||||
// 沉浸模式下并且开通了安全距离 会显示-的margin
|
||||
style_margin_container: this.propIsImmersionModel && this.propNewIsTabsSafeDistance ? `margin-top: -${ newPropTop }px;` : '',
|
||||
// 判断是否置顶
|
||||
top_up: new_top_up,
|
||||
tabs_z_index: 'z-index: 11;'
|
||||
});
|
||||
},
|
||||
// 获取选项卡高度
|
||||
get_tabs_height() {
|
||||
if (this.top_up == '1') {
|
||||
// 选择我们想要的元素
|
||||
const query = uni.createSelectorQuery();
|
||||
query
|
||||
.in(this)
|
||||
.select('.tabs-top')
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
const newPropTop = app.globalData.rpx_to_px(this.propTop);
|
||||
// data包含元素的宽度、高度等信息
|
||||
this.setData({
|
||||
tabs_seat_height: res.height + (this.propIsImmersionModel ? newPropTop + this.propStickyTop : 0),
|
||||
tabs_carousel_seat_height: (res.height + (this.propIsImmersionModel ? newPropTop + this.propStickyTop : 0)) - this.propSpacingCommonStyle.padding_top - this.propSpacingCommonStyle.margin_top, // 轮播选项卡置顶时去掉顶部间距
|
||||
});
|
||||
this.$emit('onComputerHeight', this.tabs_seat_height);
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
} else {
|
||||
this.$emit('onComputerHeight', 0);
|
||||
}
|
||||
},
|
||||
tabsZindex(val) {
|
||||
this.setData({
|
||||
tabs_z_index: `z-index: ${ val };`
|
||||
});
|
||||
},
|
||||
// 选项卡回调
|
||||
tabs_click_event(index, item) {
|
||||
let tabs_id = '';
|
||||
// 抽象出获取 tabs_id 的逻辑
|
||||
tabs_id = this.get_tabs_id(item, index);
|
||||
// 是否是商品分类页面
|
||||
const is_micro_page = item.data_type == '0';
|
||||
this.$emit('onTabsTap', tabs_id, is_micro_page);
|
||||
},
|
||||
// 获取 tabs_id
|
||||
get_tabs_id(item, index) {
|
||||
if (item.data_type === '0') {
|
||||
return index !== 0 ? item.micro_page_list?.id : '';
|
||||
} else {
|
||||
return index !== 0 ? item.classify?.id : '';
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tabs-container {
|
||||
z-index: 11;
|
||||
.tabs-top {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
.tabs-contents {
|
||||
max-width: 1600rpx !important;
|
||||
}
|
||||
@media only screen and (min-width: 1600rpx) {
|
||||
.tabs-container .tabs-top {
|
||||
left: calc(50% - 400px) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
143
components/diy/title.vue
Normal file
143
components/diy/title.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="flex-col gap-10">
|
||||
<view class="pr flex-row" :class="title_center">
|
||||
<view class="z-i flex-row align-c gap-10">
|
||||
<template v-if="!isEmpty(form.img_src) && !isEmpty(form.img_src[0].url)">
|
||||
<view class="wh-auto" :style="{'height': new_style.img_height * 2 + 'rpx' }">
|
||||
<image :src="form.img_src[0].url" class="ht-auto" mode="heightFix"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="!isEmpty(form.icon_class)">
|
||||
<iconfont :name="'icon-' + form.icon_class" :size="new_style.icon_size * 2 + 'rpx'" :color="new_style.icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</template>
|
||||
<view v-if="!isEmpty(form.title)" class="nowrap" :style="title_style" :data-value="!isEmpty(form.title_link) ? form.title_link.page : ''" @tap="url_event">{{ form.title }}</view>
|
||||
<view v-if="!isEmpty(form.subtitle) && new_style.title_line == '1'" class="text-word-break nowrap" :style="subtitle_style">{{ form.subtitle }}</view>
|
||||
</view>
|
||||
<view class="flex-row gap-10 align-c right-0 pa">
|
||||
<template v-if="form.keyword_show == '1'">
|
||||
<view class="flex-row align-c" :style="keyword_gap">
|
||||
<view v-for="item in keyword_list" :key="item.id" :style="keyword_style" :data-value="!isEmpty(item.link) ? item.link.page : ''" @tap="url_event">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="form.right_show == '1'" class="nowrap flex-row align-c" :style="right_style" :data-value="!isEmpty(form.right_link) ? form.right_link.page : ''" @tap="url_event"
|
||||
>{{ form.right_title }}
|
||||
<iconfont name="icon-arrow-right" :color="new_style.right_color" :size="new_style.right_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!isEmpty(form.subtitle) && new_style.title_line != '1'" class="text-word-break" :style="subtitle_style">{{ form.subtitle }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
title_center: '',
|
||||
subtitle_style: '',
|
||||
keyword_list: [],
|
||||
keyword_style: '',
|
||||
keyword_gap: '',
|
||||
right_style: '',
|
||||
right_size: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 判断是否为空
|
||||
isEmpty,
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
|
||||
const { keyword_color, keyword_size, right_color, right_size, common_style, title_weight, title_color, title_size, keyword_spacing = 10 } = new_style;
|
||||
// 标题样式设置
|
||||
let common_styles = '';
|
||||
if (title_weight == 'italic') {
|
||||
common_styles += `font-style: italic`;
|
||||
} else if (['bold', '500'].includes(title_weight)) {
|
||||
common_styles += `font-weight: bold`;
|
||||
}
|
||||
// 是否居中
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
title_center: new_form.is_title_center == '1' ? 'jc-c' : '',
|
||||
keyword_list: new_form.keyword_list.filter((item) => item.is_show == '1'), // 关键字
|
||||
keyword_style: `color:${keyword_color}; font-size: ${keyword_size * 2}rpx;`, // 关键字设置
|
||||
keyword_gap: !isEmpty(keyword_spacing) ? `gap: ${ keyword_spacing * 2}rpx` : 'gap: 20rpx;', // 关键字间距设置
|
||||
right_size: right_size * 2 + 'rpx', // 右边按钮设置
|
||||
right_style: `color:${right_color}; font-size: ${right_size * 2}rpx;`, //右侧按钮样式
|
||||
title_style: `color:${title_color}; font-size: ${title_size * 2}rpx; ${common_styles}`, // 标题样式设置
|
||||
subtitle_style: this.get_subtitle_style(new_style), // 副标题样式设置
|
||||
style_container: common_styles_computer(common_style), // 通用样式区
|
||||
style_img_container: common_img_computer(common_style, this.propIndex), // 通用图片样式区
|
||||
});
|
||||
},
|
||||
// 副标题样式设置
|
||||
get_subtitle_style(new_style) {
|
||||
let common_styles = '';
|
||||
if (new_style.subtitle_weight == 'italic') {
|
||||
common_styles += `font-style: italic`;
|
||||
} else if (['bold', '500'].includes(new_style.subtitle_weight)) {
|
||||
common_styles += `font-weight: bold;`;
|
||||
}
|
||||
return `color:${new_style.subtitle_color}; font-size: ${new_style.subtitle_size * 2}rpx; ${common_styles}`;
|
||||
},
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.right-0 {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.break {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
164
components/diy/user-info.vue
Normal file
164
components/diy/user-info.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<!-- 用户信息 -->
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="pr padding-xxl" :style="style">
|
||||
<view class="flex-row jc-sb align-c margin-bottom-xxl">
|
||||
<view class="flex-1 flex-row align-c gap-12">
|
||||
<image :src="(user_info.user || null) !== null ? user_info.user.avatar : user.avatar" class="circle" mode="widthFix" :style="'width:' + base_data.user_avatar_size * 2 + 'rpx;height:' + base_data.user_avatar_size * 2 + 'rpx;'" data-value="/pages/personal/personal" @tap="url_event" />
|
||||
<view class="flex-col gap-8" data-value="/pages/personal/personal" @tap="url_event">
|
||||
<view class="text-size fw-b" :style="user_name_style">{{ (user_info.user || null) !== null ? user_info.user.user_name_view : user.user_name_view }}</view>
|
||||
<view v-if="id_bool && (user_info.user || null) !== null" class="padding-horizontal-sm padding-vertical-xsss border-radius-sm" :style="number_code_style">ID:{{ user_info.user.number_code }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row align-c" :style="'gap:' + base_data.img_space * 2 + 'rpx;'">
|
||||
<view v-for="(item, index) in icon_setting" :key="index" :style="{ width: base_data.img_size + 'px', height: base_data.img_size + 'px' }" :data-value="item.link.page || ''" @tap="url_event">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="border-radius-sm" mode="scaleToFill" :style="{ width: base_data.img_size + 'px', height: base_data.img_size + 'px' }" />
|
||||
<iconfont v-else :name="'icon-' + item.icon" :size="base_data.img_size * 2 + 'rpx'" color="#666" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row jc-sa align-c">
|
||||
<template v-for="(item, index) in stats_list">
|
||||
<view v-if="config.includes(item.id)" :key="index" class="tc" :data-value="'/pages/' + item.url + '/' + item.url" @tap="url_event">
|
||||
<view class="text-size fw-b margin-bottom-sm" :style="stats_number_style">{{ item.value }}</view>
|
||||
<view class="text-size-xs" :style="stats_name_style">{{ item.name }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, gradient_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
id_bool: true,
|
||||
stats_list: [
|
||||
{ id: 'order_count', name: '订单总数', value: '100', url: 'user-order' },
|
||||
{ id: 'goods_favor_count', name: '商品收藏', value: '10', url: 'user-favor' },
|
||||
{ id: 'goods_browse_count', name: '我的足迹', value: '1000', url: 'user-goods-browse' },
|
||||
{ id: 'integral_number', name: '我的积分', value: '10000', url: 'user-integral' },
|
||||
],
|
||||
config: ['order_count', 'goods_favor_count', 'goods_browse_count', 'integral_number'],
|
||||
icon_setting: [
|
||||
{ id: '1', img: [], icon: '', link: {} },
|
||||
{ id: '2', img: [], icon: '', link: {} },
|
||||
],
|
||||
base_data: {},
|
||||
// 样式
|
||||
user_name_style: '',
|
||||
number_code_style: '',
|
||||
stats_name_style: '',
|
||||
stats_number_style: '',
|
||||
// 用户信息
|
||||
user_info: {
|
||||
user: null,
|
||||
order_count: '0',
|
||||
goods_favor_count: '0',
|
||||
goods_browse_count: '0',
|
||||
message_unread_count: '0',
|
||||
integral_number: '0',
|
||||
},
|
||||
user: {
|
||||
avatar: app.globalData.data.default_user_head_src,
|
||||
user_name_view: '用户名',
|
||||
number_code: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
const temp_base_data = {
|
||||
// 头像
|
||||
user_avatar_size: new_style.user_avatar_size,
|
||||
// 人物
|
||||
user_name_color: new_style.user_name_color,
|
||||
user_name_weight: new_style.user_name_weight,
|
||||
user_name_size: new_style.user_name_size,
|
||||
// id
|
||||
number_code_color_list: new_style.number_code_color_list,
|
||||
number_code_color: new_style.number_code_color,
|
||||
number_code_direction: new_style.number_code_direction,
|
||||
number_code_weight: new_style.number_code_weight,
|
||||
number_code_size: new_style.number_code_size,
|
||||
// 图标设置
|
||||
img_size: new_style.img_size,
|
||||
img_space: new_style.img_space,
|
||||
stats_name_color: new_style.stats_name_color,
|
||||
stats_name_weight: new_style.stats_name_weight,
|
||||
stats_name_size: new_style.stats_name_size,
|
||||
stats_number_color: new_style.stats_number_color,
|
||||
stats_number_weight: new_style.stats_number_weight,
|
||||
stats_number_size: new_style.stats_number_size,
|
||||
};
|
||||
// id样式
|
||||
const new_gradient_obj = {
|
||||
color_list: temp_base_data.number_code_color_list,
|
||||
direction: temp_base_data.number_code_direction,
|
||||
};
|
||||
let temp_stats_list = this.stats_list;
|
||||
temp_stats_list.map((item) => {
|
||||
if (new_content.config.includes(item.id)) {
|
||||
item.value = new_content.data[item.id];
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
user_info: new_content.data,
|
||||
config: new_content.config,
|
||||
icon_setting: new_content.icon_setting,
|
||||
base_data: temp_base_data,
|
||||
id_bool: new_content.config ? new_content.config.includes('number_code') : true,
|
||||
stats_list: temp_stats_list,
|
||||
// 人物名称样式
|
||||
user_name_style: 'color:' + temp_base_data.user_name_color + ';' + 'font-size:' + temp_base_data.user_name_size * 2 + 'rpx;' + 'font-weight:' + temp_base_data.user_name_weight + ';',
|
||||
number_code_style: gradient_computer(new_gradient_obj) + 'color:' + temp_base_data.number_code_color + ';' + 'font-size:' + temp_base_data.number_code_size * 2 + 'rpx;' + 'font-weight:' + temp_base_data.number_code_weight + ';',
|
||||
// 统计名称样式
|
||||
stats_name_style: 'color:' + temp_base_data.stats_name_color + ';' + 'font-size:' + temp_base_data.stats_name_size * 2 + 'rpx;' + 'font-weight:' + temp_base_data.stats_name_weight + ';',
|
||||
stats_number_style: 'color:' + temp_base_data.stats_number_color + ';' + 'font-size:' + temp_base_data.stats_number_size * 2 + 'rpx;' + 'font-weight:' + temp_base_data.stats_number_weight + ';',
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
||||
86
components/diy/video.vue
Normal file
86
components/diy/video.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<!-- 视频 -->
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="video pr" :style="style">
|
||||
<video :src="video" class="wh-auto ht-auto" :poster="video_img" objectFit="cover" style="object-fit: cover"></video>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
video_img: '',
|
||||
video: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
// 视频比例
|
||||
this.get_video_height(new_content.video_ratio);
|
||||
this.setData({
|
||||
video_img: new_content.video_img.length > 0 ? new_content.video_img[0].url : '',
|
||||
video: new_content.video.length > 0 ? new_content.video[0].url : '',
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
// 获取视频高度
|
||||
get_video_height(data) {
|
||||
uni.getSystemInfo({
|
||||
success: (res) => {
|
||||
let video_ratio = ``;
|
||||
const width = res.windowWidth;
|
||||
if (data == '4:3') {
|
||||
video_ratio = `height: ${(((width * 3) / 4) * 2).toFixed(2)}rpx;`;
|
||||
} else if (data == '1:1') {
|
||||
video_ratio = `height: ${width * 2}rpx;`;
|
||||
} else {
|
||||
// 16:9 保留两位小数
|
||||
video_ratio = `height: ${(((width * 9) / 16) * 2).toFixed(2)}rpx;`;
|
||||
}
|
||||
this.setData({
|
||||
style: video_ratio,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
Reference in New Issue
Block a user