新增营销系统、分销系统、会员功能、门店、提现功能
This commit is contained in:
26
components/canvasShow/basics/assistDiv.vue
Normal file
26
components/canvasShow/basics/assistDiv.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="div" :style="{backgroundColor:componentContent.bgColor,height:componentContent.height + 'rpx'}"></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
})
|
||||
const { componentContent } = toRefs(props)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.div{
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
106
components/canvasShow/basics/banner.vue
Normal file
106
components/canvasShow/basics/banner.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div class="banner" :class="'terminal' + terminal">
|
||||
<swiper class="swiper" :circular="true" :indicator-dots="false" :autoplay="true" :style="{'height':bannerHeight + 'rpx'}" @change="swiperChange">
|
||||
<swiper-item class="banner-item" v-for="(item,index) in bannerList" :key="index" :style="{backgroundImage: 'url('+ item.bannerUrl +')'}" @click="jumpLink(item.linkObj)">
|
||||
<!-- <div class="a-link" @click="jumpLink(item.linkObj)"><img class="img" :src="item.bannerUrl" v-show="item.bannerUrl" mode="widthFix"></div>-->
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="swiper-dots" v-if="bannerList && bannerList.length > 1">
|
||||
<text class="dot" :class="index === swiperCurrent && 'dot-active'" v-for="(dot, index) in bannerList.length"
|
||||
:key="index"></text>
|
||||
</view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import { ref, toRefs, onMounted, computed } from 'vue';
|
||||
import funMixin from '../config/mixin/funMixin'
|
||||
const { jumpLink } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
const swiperCurrent = ref(0)
|
||||
const bannerHeight = ref(0)
|
||||
onMounted(() => {
|
||||
bannerHeight.value = componentContent.value.height
|
||||
// this.$forceUpdate() // 刷新轮播图
|
||||
})
|
||||
|
||||
function swiperChange(e) {
|
||||
swiperCurrent.value = e.detail.current;
|
||||
}
|
||||
|
||||
const bannerList = computed(() => {
|
||||
return componentContent.value?.bannerData.filter(function (item) {
|
||||
return item.bannerUrl
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.banner{
|
||||
position: relative;
|
||||
padding: 0 34rpx;
|
||||
.banner-item{
|
||||
border-radius: 15rpx;
|
||||
width: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: auto 100%;
|
||||
img{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.terminal4{
|
||||
::v-deep .el-carousel{
|
||||
height: 100%;
|
||||
.el-carousel__container{
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.banner-item{
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: auto 100%;
|
||||
img{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-dots {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 20upx;
|
||||
z-index: 200;
|
||||
.dot {
|
||||
width: 12upx;
|
||||
height: 12upx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 6upx;
|
||||
opacity: 0.2;
|
||||
margin: 0 10upx;
|
||||
}
|
||||
|
||||
.dot-active {
|
||||
opacity: 1;
|
||||
width: 24upx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
148
components/canvasShow/basics/brandList.vue
Normal file
148
components/canvasShow/basics/brandList.vue
Normal file
@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<div class="brand-list warp" :class="'terminal' + terminal">
|
||||
<div class="brand-top">
|
||||
<div class="hom-title">
|
||||
{{ componentContent.title }}
|
||||
</div>
|
||||
<div v-show="componentContent.showMore" class="btn-more" @click="jumpLink(componentContent.linkObj)">查看更多</div>
|
||||
</div>
|
||||
<div class="content-warp">
|
||||
<div class="ul clearfix">
|
||||
<div class="li" :class="componentContent.imgList.length<4 && `li-${componentContent.imgList.length}`" v-for="(item, index) in componentContent.imgList" :key="index">
|
||||
<a class="item a-link" @click="jumpLink(item.linkObj)">
|
||||
<div class="imgBox">
|
||||
<image
|
||||
class="img"
|
||||
v-show="item.imgData"
|
||||
:src="item.imgData"
|
||||
:alt="item.title"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
</div>
|
||||
<h4 class="h4">{{ item.title }}</h4>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
import funMixin from '../config/mixin/funMixin.js'
|
||||
const { jumpLink } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.brand-list {
|
||||
color: #fff;
|
||||
.brand-top{
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.hom-title {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
line-height: 48rpx;
|
||||
font-weight: normal;
|
||||
}
|
||||
.btn-more{
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
padding-right: 30rpx;
|
||||
background: url("https://b2c-pro-static-dev.zkthink.com/static/images/icon-arrow.png") no-repeat right center / 20rpx 20rpx;
|
||||
}
|
||||
}
|
||||
.content-warp {
|
||||
display: flex;
|
||||
}
|
||||
.ul {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.li {
|
||||
flex: 0 0 25%;
|
||||
padding: 10rpx 0 0 10rpx;
|
||||
box-sizing: border-box;
|
||||
.item {
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
.imgBox {
|
||||
padding-bottom: 60%;
|
||||
background-color: #e8e8e8;
|
||||
position: relative;
|
||||
.img{
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
.h4 {
|
||||
font-size: 18rpx;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
font-weight: normal;
|
||||
}
|
||||
.p {
|
||||
font-size: 12rpx;
|
||||
margin: 7rpx 0 12rpx;
|
||||
}
|
||||
}
|
||||
&.li-1{
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
&.li-2{
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
&.li-3{
|
||||
flex: 0 0 33.3%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.terminal1,
|
||||
.terminal2,
|
||||
.terminal3 {
|
||||
&.brand-list {
|
||||
.content-warp {
|
||||
display: block;
|
||||
}
|
||||
.ul {
|
||||
width: auto;
|
||||
margin-left: -15rpx;
|
||||
.li {
|
||||
padding: 15rpx 0 0 15rpx;
|
||||
width: 50%;
|
||||
.item {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
110
components/canvasShow/basics/categoryList.vue
Normal file
110
components/canvasShow/basics/categoryList.vue
Normal file
@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="category-list warp" :class="'terminal' + terminal">
|
||||
<h2 class="hom-title" :style="{textAlign:componentContent.textAlign}">{{componentContent.title}}</h2>
|
||||
<div class="content-warp">
|
||||
<div class="ul clearfix" :class="{number5: componentContent.categoryData.length === 5}">
|
||||
<div class="li" v-for="(item) of componentContent.categoryData" :key="item.id">
|
||||
<a class="item a-link" @click="jumpCategory(item.id)">
|
||||
<div class="imgBox">
|
||||
<image ref="getHeight" :src="item.img" v-show="item.img" :alt="item.name" mode="aspectFit"/>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
import funMixin from '../config/mixin/funMixin.js'
|
||||
const { jumpCategory } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.category-list{
|
||||
.hom-title{
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
line-height: 48rpx;
|
||||
margin-bottom: 5rpx;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
}
|
||||
.content-warp{
|
||||
display: flex;
|
||||
.ul{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.li{
|
||||
flex: 1;
|
||||
padding: 10upx 0 0 10upx;
|
||||
box-sizing: border-box;
|
||||
.item{
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
.imgBox {
|
||||
padding-bottom: 80%;
|
||||
background-color: #cacaca;
|
||||
position: relative;
|
||||
}
|
||||
image {
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.number5 {
|
||||
display: block;
|
||||
.li {
|
||||
width: 25%;
|
||||
float: left;
|
||||
}
|
||||
.li:nth-child(1) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.category-list .content-warp .ul .li{
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
}
|
||||
.terminal1,.terminal2,.terminal3{
|
||||
&.category-list .content-warp{
|
||||
display: block;
|
||||
.ul{
|
||||
margin: -15upx 0 0 -15upx;
|
||||
width: auto;
|
||||
.li{
|
||||
flex: 0 0 50%;
|
||||
padding: 15upx 0 0 15upx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
216
components/canvasShow/basics/coupon/index.vue
Normal file
216
components/canvasShow/basics/coupon/index.vue
Normal file
@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<div class="coupon-box" >
|
||||
<div class="coupon-list coupon-flex coupon-swiper" v-if="componentContent.arrangeType == '横向滑动'">
|
||||
<swiper class="swiper"
|
||||
:disable-touch="couponsData.length < 3"
|
||||
:circular="false"
|
||||
:indicator-dots="false"
|
||||
:autoplay="couponsData.length > 2"
|
||||
:display-multiple-items="2"
|
||||
:previous-margin="swiperCurrent === couponsData.length - 2?'32rpx':'0rpx'"
|
||||
:next-margin="swiperCurrent === couponsData.length - 2?'0rpx':'32rpx'">
|
||||
<swiper-item class="swiper-slide" v-for="(item, index) in couponsData" :key="index">
|
||||
<couponItem :item="item" :componentContent="componentContent" @receive="receiveCoupon" />
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</div>
|
||||
<div class="coupon-list" v-else :class="componentContent.arrangeType === '多行多列' && 'coupon-flex'">
|
||||
<couponItem class="item" v-for="(item, index) in couponsData" :key="index" :item="item" :componentContent="componentContent" @receive="receiveCoupon" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import commonMixin from './mixin';
|
||||
import couponItem from './item.vue';
|
||||
import { toRefs } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
typeId: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
shopId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
});
|
||||
const { typeId, shopId, componentContent } = toRefs(props);
|
||||
const { couponsData, receiveCoupon } = commonMixin(componentContent, typeId, shopId);
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
options: {
|
||||
styleIsolation: 'shared'
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.coupon-box{
|
||||
padding: 0 35rpx;
|
||||
::v-deep .coupon-list{
|
||||
.item{
|
||||
margin-top: 24rpx;
|
||||
display: block;
|
||||
&:first-child{
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
.coupon-item {
|
||||
width: 100%;
|
||||
height: 160rpx;
|
||||
background: url('https://b2c-pro-static-dev.zkthink.com/static/images/canvas/bg-coupon-l.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.discount{
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
font-size: 68rpx;
|
||||
line-height: 64rpx;
|
||||
font-weight: bold;
|
||||
.unit{
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.info{
|
||||
font-size: 38rpx;
|
||||
.type{
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
line-height: 45rpx;
|
||||
}
|
||||
.tip{
|
||||
font-size: 24rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.button{
|
||||
width: 144rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #ee6d46;
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.disable{
|
||||
background: #666666;
|
||||
}
|
||||
.expired{
|
||||
background: #999999;
|
||||
}
|
||||
|
||||
.coupon-left{
|
||||
width: 206rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.coupon-right{
|
||||
flex: 1;
|
||||
display: flex;
|
||||
padding: 0 32rpx;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
&.coupon-flex{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
.item:nth-child(2){
|
||||
margin-top: 0;
|
||||
}
|
||||
.coupon-item {
|
||||
width: 333rpx;
|
||||
height: 140rpx;
|
||||
background-image: url('https://b2c-pro-static-dev.zkthink.com/static/images/canvas/bg-coupon-m.png');
|
||||
.coupon-left{
|
||||
width: 147rpx;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.type{
|
||||
font-size: 20rpx;
|
||||
font-weight: bold;
|
||||
line-height: 28rpx;
|
||||
}
|
||||
}
|
||||
.coupon-right{
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
}
|
||||
.discount{
|
||||
font-size: 32rpx;
|
||||
line-height: 45rpx;
|
||||
.unit{
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.info{
|
||||
.tip{
|
||||
font-size: 20rpx;
|
||||
line-height: 36rpx;
|
||||
margin-bottom: 9rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.button{
|
||||
width: 132rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 4rpx;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.coupon-swiper{
|
||||
.swiper{
|
||||
height: 140rpx;
|
||||
}
|
||||
.swiper-slide{
|
||||
width: 310rpx;
|
||||
.coupon-item {
|
||||
width: 310rpx;
|
||||
background-image: url('https://b2c-pro-static-dev.zkthink.com/static/images/canvas/bg-coupon-s.png');
|
||||
margin-bottom: 0;
|
||||
.coupon-left{
|
||||
width: 130rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .uni-swiper-dots{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
bottom: 27rpx;
|
||||
.uni-swiper-dot{
|
||||
width: 24upx;
|
||||
height: 4upx;
|
||||
background: #fff;
|
||||
opacity: 0.5;
|
||||
border-radius: 2upx;
|
||||
margin: 0 5upx;
|
||||
&-active{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
57
components/canvasShow/basics/coupon/item.vue
Normal file
57
components/canvasShow/basics/coupon/item.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="coupon-item">
|
||||
<div class="coupon-left">
|
||||
<!-- 折扣力度 -->
|
||||
<div class="discount">
|
||||
<div class="unit pre-unit" v-if="item.couponType === 1">
|
||||
¥
|
||||
</div>
|
||||
{{item.couponType === 1 ? item.couponValue : item.discount}}
|
||||
<div class="unit" v-if="item.couponType === 2">
|
||||
折
|
||||
</div>
|
||||
</div>
|
||||
<div class="type" v-if="componentContent.arrangeType === '多行多列'">
|
||||
{{item.couponType === 1 ? '满减券' : '折扣券'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="coupon-right">
|
||||
<div class="info">
|
||||
<div class="type" v-if="componentContent.arrangeType === '一行一个'">
|
||||
{{item.couponType === 1 ? '满减券' : '折扣券'}}
|
||||
</div>
|
||||
<div class="tip">
|
||||
{{item.threshold!==0?`(实付${item.threshold}元使用)`:'无门槛使用'}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- button -->
|
||||
<div class="button get-coupon" @click="receiveCoupon(item)">
|
||||
领取
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {toRefs} from "vue";
|
||||
|
||||
const emits = defineEmits(['receive'])
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
});
|
||||
const { item, componentContent } = toRefs(props);
|
||||
function receiveCoupon (item) {
|
||||
emits('receive', item)
|
||||
}
|
||||
|
||||
</script>
|
122
components/canvasShow/basics/coupon/mixin.js
Normal file
122
components/canvasShow/basics/coupon/mixin.js
Normal file
@ -0,0 +1,122 @@
|
||||
import api from '../../config/api'
|
||||
import { funMixin } from '../../config/mixin'
|
||||
import { ref, onMounted } from 'vue';
|
||||
import cookie from '@/utils/cookie'
|
||||
|
||||
export default function (componentContent, typeId, shopId) {
|
||||
const { sendReq, beforeGetData, afterGetData, jumpStore } = funMixin()
|
||||
const couponsData = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
|
||||
// 获取优惠券列表
|
||||
function getData () {
|
||||
if (
|
||||
componentContent.value.selectedCoupon &&
|
||||
componentContent.value.selectedCoupon.length > 0
|
||||
) {
|
||||
beforeGetData()
|
||||
let _url = `${api.getCoupons}?isPage=2&ids=${componentContent.value.selectedCoupon}`
|
||||
const params = {
|
||||
method: 'GET',
|
||||
url: _url,
|
||||
}
|
||||
sendReq(
|
||||
params,
|
||||
(res) => {
|
||||
afterGetData()
|
||||
couponsData.value = res.data.list
|
||||
},
|
||||
() => {
|
||||
afterGetData()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
couponsData.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 领取优惠券
|
||||
async function receiveCoupon (item) {
|
||||
var token = cookie.get('accessToken')
|
||||
if (typeof uni !== 'undefined') {
|
||||
if (token) {
|
||||
const params = {
|
||||
url: `${api.takeCoupon}${item.id}`,
|
||||
method: 'GET',
|
||||
}
|
||||
sendReq(
|
||||
params,
|
||||
(res) => {
|
||||
if (res.code !== 0) {
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
icon: 'none'
|
||||
})
|
||||
} else {
|
||||
getData()
|
||||
uni.showToast({
|
||||
title: '领取成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
() => {
|
||||
if (res.code !== 0) {
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '请先登录',
|
||||
icon: 'none'
|
||||
})
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/guid'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (token) {
|
||||
const params = {
|
||||
url: `${api.takeCoupon}${item.id}`,
|
||||
method: 'GET',
|
||||
}
|
||||
sendReq(params).then(res => {
|
||||
ElMessage({
|
||||
message: '领取成功!',
|
||||
type: 'success'
|
||||
})
|
||||
getData()
|
||||
}).catch(res => {
|
||||
if (res.data.code !== '200') {
|
||||
ElMessage({
|
||||
message: res.data.message,
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ElMessage({
|
||||
message: '请先登录'
|
||||
})
|
||||
// 登录弹框
|
||||
// store.commit('IS_LOGIN', false) // 清除顶部个人中心数据
|
||||
// store.commit('SHOW_LOGIN') // 调用登录弹框
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
componentContent,
|
||||
couponsData,
|
||||
receiveCoupon,
|
||||
jumpStore
|
||||
}
|
||||
}
|
237
components/canvasShow/basics/custom.vue
Normal file
237
components/canvasShow/basics/custom.vue
Normal file
@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<div class="custom" :class="'terminal' + terminal">
|
||||
<div class="rowLayout" v-if="componentContent.layoutType ==='L1' || componentContent.layoutType ==='L2' || componentContent.layoutType ==='L3' || componentContent.layoutType ==='L4'">
|
||||
<div class="customLayout" :style="{'padding':'0 ' + componentContent.pageSpacing + 'px','marginLeft':(-componentContent.imgClearance) +'px'}">
|
||||
<div class="ul clearfix" :class="'layout'+componentContent.layoutType">
|
||||
<div class='li' v-for="(item,index) of componentContent.imgData" :key="index" :style="{'width':getItemValue(item.width) + '%','height':getItemValue(item.height) + '%','left':getItemValue(item.left) + '%','top':getItemValue(item.top) + '%','paddingLeft':componentContent.imgClearance +'px'}">
|
||||
<a class="a-link" @click="jumpLink(item.linkObj)"><image class="img" :src="item.src" v-if="item.src" mode="widthFix" /></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else :style="{'padding':'0 ' + componentContent.pageSpacing + 'upx'}">
|
||||
<div class="boxLayout" :style="{'paddingBottom':componentContent.maxH !== 0?getItemValue(componentContent.maxH) + '%': (componentContent.layoutType === 'L1T1B2' ? '50%' : '100%')}">
|
||||
<div class="boxLayoutInner">
|
||||
<div class="boxWarp">
|
||||
<div class="customLayout" :style="{'marginLeft':(-componentContent.imgClearance) +'px','top':(-componentContent.imgClearance) +'px'}">
|
||||
<div class="ul clearfix" :class="'layout'+componentContent.layoutType">
|
||||
<div class='li' v-for="(item,index) of componentContent.imgData" :key="index" :style="{'width':getItemValue(item.width) + '%','height':getItemValue(item.height) + '%','left':getItemValue(item.left) + '%','top':getItemValue(item.top) + '%','padding':componentContent.imgClearance +'px 0 0 ' + componentContent.imgClearance +'px'}">
|
||||
<a class="a-link" @click="jumpLink(item.linkObj)"><image class="img" :src="item.src" v-if="item.src" mode="aspectFit" /></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
import funMixin from '../config/mixin/funMixin.js'
|
||||
const { jumpLink } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
// 计算生成格子百分比
|
||||
function getItemValue (val) {
|
||||
const density = parseInt(componentContent.value.density)
|
||||
if (val === 0 || density === 0) {
|
||||
return 0
|
||||
}
|
||||
return ((val / density) * 10000) / 100.0 // 小数点后两位百分比
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom{
|
||||
//width: 710upx;
|
||||
//margin: 0 auto;
|
||||
.boxLayout{
|
||||
position: relative;
|
||||
.boxLayoutInner{
|
||||
padding-bottom: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.boxWarp{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.customLayout{
|
||||
position: relative;
|
||||
.ul{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
position: relative;
|
||||
}
|
||||
.li{
|
||||
box-sizing: border-box;
|
||||
.img{
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
.a-link {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.layoutL1 .li{
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
.layoutL2 .li{
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
.layoutL3 .li{
|
||||
flex: 0 0 33.3%;
|
||||
}
|
||||
.layoutL4 .li{
|
||||
flex: 0 0 25%;
|
||||
}
|
||||
.layoutT2B2{
|
||||
padding-bottom: 100%;
|
||||
.li{
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
position: absolute;
|
||||
.img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
&:nth-child(1){
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
&:nth-child(2){
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
&:nth-child(3){
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
&:nth-child(4){
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.layoutL1R2{
|
||||
padding-bottom: 100%;
|
||||
.li{
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
position: absolute;
|
||||
.img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
&:nth-child(1){
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
&:nth-child(2){
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
&:nth-child(3){
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.layoutT1B2{
|
||||
padding-bottom: 100%;
|
||||
.li{
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
position: absolute;
|
||||
.img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
&:nth-child(1){
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
&:nth-child(2){
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
&:nth-child(3){
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.layoutL1T1B2{
|
||||
padding-bottom: 50%;
|
||||
.li{
|
||||
position: absolute;
|
||||
.img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
&:nth-child(1){
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
&:nth-child(2){
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
&:nth-child(3){
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
width: 25%;
|
||||
height: 50%;
|
||||
}
|
||||
&:nth-child(4){
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 25%;
|
||||
height: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.layoutaverage{
|
||||
padding-bottom: 100%;
|
||||
.li{
|
||||
position: absolute;
|
||||
.img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
// #ifdef MP
|
||||
.layoutaverage{
|
||||
padding-bottom: 91%;
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
</style>
|
171
components/canvasShow/basics/discount/app/index.vue
Normal file
171
components/canvasShow/basics/discount/app/index.vue
Normal file
@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div class="spike">
|
||||
<div class="spike-card" v-if="productList?.length>0">
|
||||
<div class="spike-card-top">
|
||||
<h2 class="spike-card-top-title">
|
||||
限时折扣
|
||||
</h2>
|
||||
<div class="spike-card-top-time" v-if="activityData?.state===2">
|
||||
<div class="session">活动已结束</div>
|
||||
</div>
|
||||
<div class="spike-card-top-time" v-else-if="count?.length > 0">
|
||||
<div class="session">距活动{{count[0]}}还有</div>
|
||||
<div class="time">{{count[1]}}:{{count[2]}}:{{count[3]}}</div>
|
||||
</div>
|
||||
<a v-show="componentContent.showMore" class="btn-more" @click="jumpDiscount(componentContent.id)">查看更多</a>
|
||||
</div>
|
||||
<div class="spike-card-list">
|
||||
<div class="spike-card-item" v-for='item in productList.slice(0,3)' :key='item.productId' @click="jumpProductDetail(item)">
|
||||
<div class="spike-card-item-img">
|
||||
<image :src="item.image" alt="" />
|
||||
</div>
|
||||
<div class="spike-card-item-info">
|
||||
<h3 class="name">
|
||||
{{item.storeName}}
|
||||
</h3>
|
||||
<div class="price-warp">
|
||||
<div class="price">¥{{item.price}}</div>
|
||||
<!-- <div class="original-price">
|
||||
¥ {{item.originalPrice}}
|
||||
</div> -->
|
||||
<div class="stock">
|
||||
限量{{item.stock}}件
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import commonMixin from '../mixin'
|
||||
import { toRefs } from 'vue';
|
||||
const props = defineProps({
|
||||
typeId: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
shopId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { typeId, shopId, componentContent } = toRefs(props)
|
||||
const { activityData, productList, count, jumpProductDetail, jumpDiscount } = commonMixin(componentContent, typeId, shopId)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.spike{
|
||||
&-card{
|
||||
border-radius: 20rpx;
|
||||
margin: 0 34rpx;
|
||||
&-top{
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 17rpx;
|
||||
&-title{
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-right: 25rpx;
|
||||
font-weight: normal;
|
||||
}
|
||||
&-time{
|
||||
height: 40rpx;
|
||||
border-radius: 21px;
|
||||
border: 1px solid #EE6D46;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
.session{
|
||||
height: 100%;
|
||||
line-height: 40rpx;
|
||||
background: #EE6D46;
|
||||
font-size: 20rpx;
|
||||
color: #FFFFFF;
|
||||
padding: 0 15rpx;
|
||||
border-radius: 21rpx;
|
||||
}
|
||||
.time{
|
||||
font-size: 20rpx;
|
||||
color: #EE6D46;
|
||||
padding: 0 14rpx 0 10rpx;
|
||||
}
|
||||
}
|
||||
.btn-more{
|
||||
position: absolute;
|
||||
right: 8rpx;
|
||||
top: 0rpx;
|
||||
line-height: 40rpx;
|
||||
padding-right: 30rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
background: url("https://b2c-pro-static-dev.zkthink.com/static/images/icon-arrow.png") no-repeat right center / 20rpx 20rpx;
|
||||
}
|
||||
}
|
||||
&-list{
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
padding: 20rpx;
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
&-item{
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
flex: 0 0 203rpx;
|
||||
margin-right: 18rpx;
|
||||
&-img{
|
||||
width: 203rpx;
|
||||
height: 203rpx;
|
||||
image{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
&-info{
|
||||
width: 203rpx;
|
||||
.name{
|
||||
font-size: 30rpx;
|
||||
font-weight: normal;
|
||||
line-height: 40rpx;
|
||||
color: #333333;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
padding: 15rpx 0 6rpx;
|
||||
}
|
||||
.price-warp{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.price{
|
||||
font-size: 32rpx;
|
||||
color: #EE6D46;
|
||||
padding-right: 10rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
.original-price{
|
||||
font-size: 20rpx;
|
||||
line-height: 28rpx;
|
||||
color: #CCCCCC;
|
||||
display: inline-block;
|
||||
}
|
||||
.stock{
|
||||
line-height: 1em;
|
||||
display: inline-block;
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
102
components/canvasShow/basics/discount/mixin.js
Normal file
102
components/canvasShow/basics/discount/mixin.js
Normal file
@ -0,0 +1,102 @@
|
||||
import api from '../../config/api'
|
||||
import { funMixin } from '../../config/mixin'
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
export default function (componentContent, typeId, shopId) {
|
||||
const { sendReq, beforeGetData, afterGetData, jumpProductDetail, jumpDiscount } = funMixin()
|
||||
const activityData = ref({})
|
||||
const productList = ref([])
|
||||
const count = ref([])
|
||||
const timer = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
if (componentContent.value.id) {
|
||||
getProList()
|
||||
getActivit()
|
||||
} else {
|
||||
productList.value = []
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(timer.value)
|
||||
})
|
||||
|
||||
function getProList () {
|
||||
beforeGetData()
|
||||
const params = {
|
||||
method: 'POST',
|
||||
url: api.getActivityProduct,
|
||||
data: {
|
||||
isPage: 2,
|
||||
ids: [componentContent.value.id]
|
||||
}
|
||||
}
|
||||
sendReq(
|
||||
params,
|
||||
(res) => {
|
||||
afterGetData()
|
||||
productList.value = res.data.list
|
||||
},
|
||||
() => {
|
||||
afterGetData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function getActivit () {
|
||||
beforeGetData()
|
||||
const params = {
|
||||
method: 'GET',
|
||||
url: `${api.getActivity}?id=${componentContent.value.id}`,
|
||||
}
|
||||
sendReq(
|
||||
params,
|
||||
(res) => {
|
||||
afterGetData()
|
||||
activityData.value = res.data
|
||||
getTime()
|
||||
},
|
||||
() => {
|
||||
afterGetData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function getTime () {
|
||||
const date = new Date().getTime()
|
||||
let startTime = activityData.value.startTime
|
||||
let endTime = activityData.value.endTime
|
||||
let time = 0
|
||||
if (activityData.value.state === 0) {
|
||||
time = startTime - date // 未开始
|
||||
} else if(activityData.value.state === 1) {
|
||||
time = endTime - date // 进行中
|
||||
}
|
||||
let countDownInterval = setInterval(()=>{
|
||||
countDown(time)
|
||||
time -= 1000
|
||||
if(time <= 0){
|
||||
clearInterval(countDownInterval)
|
||||
activityData.value.state ++
|
||||
}
|
||||
},1000)
|
||||
}
|
||||
function countDown (time) {
|
||||
const fn = (v) => (v < 10 ? `0${v}` : v)
|
||||
const t = parseInt(time / 1000)
|
||||
const text = activityData.value.state === 0 ? '开始' : '结束'
|
||||
const hour = parseInt(t / 3600)
|
||||
const min = parseInt((t % 3600) / 60)
|
||||
const s = t % 60
|
||||
count.value = [text, fn(hour), fn(min), fn(s)]
|
||||
}
|
||||
|
||||
return {
|
||||
activityData,
|
||||
productList,
|
||||
count,
|
||||
jumpProductDetail,
|
||||
jumpDiscount
|
||||
}
|
||||
}
|
210
components/canvasShow/basics/group/app/index.vue
Normal file
210
components/canvasShow/basics/group/app/index.vue
Normal file
@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<div class="group-list">
|
||||
<div class="group-warp">
|
||||
<div class="header">
|
||||
<div class="header-warp">
|
||||
<div class="title">超值拼团</div>
|
||||
<text class="sub-title">拼着买更划算</text>
|
||||
</div>
|
||||
<a v-show="componentContent.showMore" class="btn-all a-link" @click="jumpGroupWorks(componentContent.id)">查看更多</a>
|
||||
</div>
|
||||
<div v-if="productList.length > 0">
|
||||
<swiper class="swiper pro-box"
|
||||
:disable-touch="productList.length < 3"
|
||||
:circular="false"
|
||||
:indicator-dots="false"
|
||||
:autoplay="productList.length > 2"
|
||||
:display-multiple-items="2"
|
||||
:previous-margin="swiperCurrent === productList.length - 2?'60rpx':'0rpx'"
|
||||
:next-margin="swiperCurrent === productList.length - 2?'0rpx':'60rpx'"
|
||||
@change="swiperChange">
|
||||
<swiper-item class="swiper-slide pro-item-warp" v-for="(item,index) in productList" :key="index" @click="jumpProductDetail(item)">
|
||||
<div class="pro-item-inner">
|
||||
<div class="pro-item">
|
||||
<div class="pro-item-img">
|
||||
<image class="img default-img" :src="item.image" />
|
||||
</div>
|
||||
<div class="pro-item-info">
|
||||
<div class="name">{{item.storeName}}</div>
|
||||
<div class="price">¥{{item.price}}</div>
|
||||
<div class="group-num">{{item.person||0}}人团</div>
|
||||
<div class="btn-buy">立刻拼团</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import {ref, toRefs} from 'vue';
|
||||
import commonMixin from '../mixin'
|
||||
|
||||
const props = defineProps({
|
||||
typeId: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
shopId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
},
|
||||
}
|
||||
})
|
||||
const { typeId, shopId, componentContent } = toRefs(props)
|
||||
const { productList, jumpProductDetail, jumpGroupWorks } = commonMixin(componentContent, typeId, shopId)
|
||||
const swiperCurrent = ref(0)
|
||||
|
||||
function swiperChange(e) {
|
||||
swiperCurrent.value = e.detail.current;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.group-list{
|
||||
padding: 0 34rpx;
|
||||
.header{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 20rpx;
|
||||
.header-warp{
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
.title{
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.sub-title{
|
||||
font-size: 24rpx;
|
||||
color: #EE6D46;
|
||||
}
|
||||
}
|
||||
.btn-all{
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
padding-right: 30rpx;
|
||||
background: url("https://b2c-pro-static-dev.zkthink.com/static/images/icon-arrow.png") no-repeat right center / 20upx 20upx;
|
||||
}
|
||||
}
|
||||
.pro-box{
|
||||
height: 462upx;
|
||||
display: flex;
|
||||
&.swiper-disabled{
|
||||
.uni-swiper-wrapper{
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
.pro-item{
|
||||
width: 290upx;
|
||||
background: #FFFFFF;
|
||||
.pro-item-img{
|
||||
height: 290upx;
|
||||
.img{
|
||||
width: 100%;
|
||||
height: 290upx;
|
||||
}
|
||||
}
|
||||
.pro-item-info{
|
||||
padding: 14rpx 20rpx 30rpx;
|
||||
position: relative;
|
||||
.name{
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #333333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 5upx;
|
||||
}
|
||||
.price{
|
||||
color: #EE6D46;
|
||||
font-size: 30upx;
|
||||
line-height: 42upx;
|
||||
}
|
||||
.group-num{
|
||||
font-size: 24rpx;
|
||||
line-height: 33rpx;
|
||||
color: #999999;
|
||||
display: block;
|
||||
}
|
||||
.btn-buy{
|
||||
width: 140rpx;
|
||||
height: 50rpx;
|
||||
background: #EE6D46;
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
bottom: 30rpx;
|
||||
font-size: 24rpx;
|
||||
color: #FFFFFF;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .uni-swiper-dots{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
bottom: 27px;
|
||||
.uni-swiper-dot{
|
||||
width: 24upx;
|
||||
height: 4upx;
|
||||
background: #fff;
|
||||
opacity: 0.5;
|
||||
border-radius: 2upx;
|
||||
margin: 0 5upx;
|
||||
&-active{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//.pagination{
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// ::v-deep .swiper-pagination-bullet{
|
||||
// width: 24upx;
|
||||
// height: 4upx;
|
||||
// background: #fff;
|
||||
// opacity: 0.5;
|
||||
// border-radius: 2upx;
|
||||
// margin: 0 5upx;
|
||||
// }
|
||||
// ::v-deep .swiper-pagination-bullet-active{
|
||||
// opacity: 1;
|
||||
// }
|
||||
//}
|
||||
.swiper-dots {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 15rpx;
|
||||
z-index: 66;
|
||||
.dot {
|
||||
width: 24upx;
|
||||
height: 4upx;
|
||||
background: #fff;
|
||||
opacity: 0.5;
|
||||
border-radius: 2upx;
|
||||
margin: 0 10upx;
|
||||
}
|
||||
|
||||
.dot-active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
55
components/canvasShow/basics/group/mixin.js
Normal file
55
components/canvasShow/basics/group/mixin.js
Normal file
@ -0,0 +1,55 @@
|
||||
import api from '../../config/api'
|
||||
import {
|
||||
funMixin
|
||||
} from '../../config/mixin'
|
||||
import {
|
||||
ref,
|
||||
onMounted
|
||||
} from 'vue';
|
||||
|
||||
export default function (componentContent, typeId, shopId) {
|
||||
const {
|
||||
sendReq,
|
||||
beforeGetData,
|
||||
afterGetData,
|
||||
jumpProductDetail,
|
||||
jumpGroupWorks
|
||||
} = funMixin()
|
||||
const productList = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
|
||||
function getData () {
|
||||
if (componentContent.value.id) {
|
||||
beforeGetData()
|
||||
const params = {
|
||||
method: 'POST',
|
||||
url: api.getActivityProduct,
|
||||
data: {
|
||||
isPage: 2,
|
||||
type: 1
|
||||
}
|
||||
}
|
||||
sendReq(
|
||||
params,
|
||||
(res) => {
|
||||
afterGetData()
|
||||
productList.value = res.data.list
|
||||
},
|
||||
() => {
|
||||
afterGetData()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
productList.value = []
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
productList,
|
||||
jumpProductDetail,
|
||||
jumpGroupWorks
|
||||
}
|
||||
}
|
142
components/canvasShow/basics/header/app/index.vue
Normal file
142
components/canvasShow/basics/header/app/index.vue
Normal file
@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div class="header">
|
||||
<div class="header-row">
|
||||
<image
|
||||
class="logo"
|
||||
:src="componentContent.imageUrl"
|
||||
mode="heightFix"
|
||||
/>
|
||||
<div
|
||||
class="search-col"
|
||||
@click="toSearch(item)">
|
||||
<div class="search-input">
|
||||
<div v-if="componentContent.keyList.length === 0">搜索商品</div>
|
||||
<swiper
|
||||
v-else
|
||||
class="swiper-wrapper"
|
||||
:circular="true"
|
||||
:indicator-dots="false"
|
||||
:autoplay="true"
|
||||
:vertical="true">
|
||||
<swiper-item
|
||||
class="swiper-slide"
|
||||
v-for="(item,index) in componentContent.keyList"
|
||||
:key="index">
|
||||
<div class="a-link">{{ item }}</div>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-nav-warp">
|
||||
<div
|
||||
class="tabs-nav"
|
||||
scroll-x="true">
|
||||
<div class="ul">
|
||||
<div
|
||||
v-for="(item, index) in componentContent.tabs"
|
||||
:key="index"
|
||||
class="li"
|
||||
:class="{ on: activeTab === index + 1 }"
|
||||
@click="jumpLink(item.link)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, toRefs } from 'vue';
|
||||
import commonMixin from '../mixin';
|
||||
|
||||
const props = defineProps({
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {componentContent} = toRefs(props);
|
||||
const {jumpLink, toSearch} = commonMixin();
|
||||
const activeTab = ref(0);
|
||||
</script>
|
||||
|
||||
<style
|
||||
lang="scss"
|
||||
scoped>
|
||||
.header {
|
||||
padding: 11rpx 34rpx 0;
|
||||
|
||||
.logo {
|
||||
// width: 280px;
|
||||
height: 40rpx;
|
||||
margin-bottom: 11rpx;
|
||||
}
|
||||
|
||||
.search-col {
|
||||
height: 60rpx;
|
||||
overflow: hidden;
|
||||
border-radius: 30rpx;
|
||||
padding: 0 30rpx 0 90rpx;
|
||||
background: #FFFFFF url("https://b2c-pro-static-dev.zkthink.com/static/images/icon-search.png") no-repeat 30rpx center / auto 30rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 60rpx;
|
||||
color: #999999;
|
||||
margin: 24rpx 0;
|
||||
.search-input{
|
||||
width: 100%;
|
||||
}
|
||||
.swiper-wrapper{
|
||||
width: 100%;
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-nav-warp {
|
||||
margin-top: 20rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.tabs-nav {
|
||||
.ul {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow: auto;
|
||||
|
||||
.li {
|
||||
margin-left: 48rpx;
|
||||
font-size: 28rpx;
|
||||
color: #262626;
|
||||
position: relative;
|
||||
padding-bottom: 18rpx;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.on, &:hover {
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
width: 48rpx;
|
||||
height: 6rpx;
|
||||
background: #F26E47;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -24rpx;
|
||||
bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
9
components/canvasShow/basics/header/mixin.js
Normal file
9
components/canvasShow/basics/header/mixin.js
Normal file
@ -0,0 +1,9 @@
|
||||
import { funMixin } from '../../config/mixin'
|
||||
|
||||
export default function () {
|
||||
const { jumpLink, toSearch } = funMixin()
|
||||
return {
|
||||
jumpLink,
|
||||
toSearch
|
||||
}
|
||||
}
|
116
components/canvasShow/basics/imageText.vue
Normal file
116
components/canvasShow/basics/imageText.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div class="imageText warp" :class="['terminal'+terminal,'pos-' + componentContent.positionValue]">
|
||||
<div class="img-box img-left">
|
||||
<a class="item a-link" @click="jumpLink(componentContent.linkObj)"><image class="img" :src="componentContent.imageUrl" alt="" mode="aspectFit"/></a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<h3 class="h3">{{componentContent.title}}</h3>
|
||||
<div v-html="componentContent.content"></div>
|
||||
</div>
|
||||
<div class="img-box img-right">
|
||||
<a class="item a-link" @click="jumpLink(componentContent.linkObj)"><image class="img" :src="componentContent.imageUrl" alt="" mode="aspectFit"/></a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
import funMixin from '../config/mixin/funMixin.js'
|
||||
const { jumpLink } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.imageText{
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20upx 0;
|
||||
.img-box{
|
||||
width: 50%;
|
||||
padding-bottom: 30%;
|
||||
background-color: #cacaca;
|
||||
position: relative;
|
||||
.img{
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
.text{
|
||||
width: 40%;
|
||||
.h3{
|
||||
font-size: 30upx;
|
||||
margin-bottom: 24upx;
|
||||
}
|
||||
.p{
|
||||
font-size: 16upx;
|
||||
}
|
||||
}
|
||||
&.pos-top{
|
||||
display: block;
|
||||
text-align: center;
|
||||
.img-box{
|
||||
width: 100%;
|
||||
}
|
||||
.text{
|
||||
width: 100%;
|
||||
margin-top: 30upx;
|
||||
}
|
||||
.img-right{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.pos-bottom{
|
||||
display: block;
|
||||
text-align: center;
|
||||
.img-box{
|
||||
width: 100%;
|
||||
}
|
||||
.text{
|
||||
width: 100%;
|
||||
margin-bottom: 30upx;
|
||||
}
|
||||
.img-left{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.pos-left{
|
||||
.img-right{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.pos-right{
|
||||
.text{
|
||||
padding-left: 20upx;
|
||||
}
|
||||
.img-left{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.terminal1,.terminal2,.terminal3{
|
||||
width: 710upx;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
141
components/canvasShow/basics/imageTextList.vue
Normal file
141
components/canvasShow/basics/imageTextList.vue
Normal file
@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<div class="hom-pro-list warp" :class="'terminal'+terminal">
|
||||
<div class="title">
|
||||
<h2 class="h2" :style="{textAlign:componentContent.textAlign}">{{componentContent.title}}</h2>
|
||||
</div>
|
||||
<div class="ul clearfix" :class="{imgTextNum4: componentContent.imgTextData.length === 4, imgTextNum5: componentContent.imgTextData.length === 5, imgTextStyle: componentContent.imgTextData.length >= 6 || componentContent.imgTextData.length === 3}">
|
||||
<div class="li" v-for="(item,index) in componentContent.imgTextData" :key="index">
|
||||
<a class="item a-link" @click="jumpLink(item.linkObj)">
|
||||
<div class="itemImgBox" v-show="item.isShow">
|
||||
<div class="imgBox">
|
||||
<image class="img" ref="getHeight" :src="item.imgData" v-show="item.imgData" :alt="item.title" mode="aspectFit"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text">
|
||||
<h4 class="h4">{{item.title}}</h4>
|
||||
<p class="p">{{item.describe}}</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
import funMixin from '../config/mixin/funMixin.js'
|
||||
const { jumpLink } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hom-pro-list{
|
||||
min-height: 450rpx;
|
||||
.title {
|
||||
margin-bottom: 17rpx;
|
||||
position: relative;
|
||||
.h2 {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
line-height: 48rpx;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
.ul{
|
||||
margin: -15rpx 0 0 -15rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.li{
|
||||
width: 0;
|
||||
flex: 0 0 50%;
|
||||
padding: 15rpx 0 0 15rpx;
|
||||
box-sizing: border-box;
|
||||
.item{
|
||||
.itemImgBox {
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
.imgBox {
|
||||
padding-bottom: 80%;
|
||||
background-color: #cacaca;
|
||||
position: relative;
|
||||
.img {
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.text{
|
||||
padding:16rpx 20rpx;
|
||||
text-align: center;
|
||||
.h4{
|
||||
//line-height: 25upx;
|
||||
font-size: 28rpx;
|
||||
overflow: hidden;
|
||||
color: #333333;
|
||||
font-weight: normal;
|
||||
}
|
||||
.p{
|
||||
font-size: 20rpx;
|
||||
color: #666666;
|
||||
padding: 5rpx 0 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.imgTextNum4 {
|
||||
.li {
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
}
|
||||
.imgTextNum5 {
|
||||
.li {
|
||||
flex: 0 0 33.33%;
|
||||
}
|
||||
.li:nth-child(1) {
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
.li:nth-child(2) {
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
}
|
||||
.imgTextStyle {
|
||||
.li {
|
||||
flex: 0 0 33.33%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.hom-pro-list .ul .li{
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
}
|
||||
.terminal1,.terminal2,.terminal3{
|
||||
width: 710upx;
|
||||
margin: 0 auto;
|
||||
&.hom-pro-list .ul .li{
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
}
|
||||
</style>
|
101
components/canvasShow/basics/imageTextNav.vue
Normal file
101
components/canvasShow/basics/imageTextNav.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div class="ul image-text-nav" :class="'terminal' + terminal">
|
||||
<div
|
||||
v-for="(item, index) in componentContent.imgTextData"
|
||||
:key="index"
|
||||
class="li"
|
||||
:style="{ flex: '0 0 ' + getItemValue() + '%' }"
|
||||
@click="jumpLink(item.linkObj)"
|
||||
>
|
||||
<div class="img-box">
|
||||
<div class="img-box-inner">
|
||||
<image class="img" :src="item.img" fit="contain" />
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="h4">{{ item.title }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
import { funMixin } from '../config/mixin'
|
||||
const { jumpLink } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
// 计算生成格子百分比
|
||||
function getItemValue () {
|
||||
const len = parseInt(componentContent.value.imgTextData.length)
|
||||
if (len === 0) {
|
||||
return 0
|
||||
} else {
|
||||
return ((1 / len) * 10000) / 100.0
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.image-text-nav {
|
||||
min-height: 102rpx;
|
||||
width: 680rpx;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
padding: 21rpx 0;
|
||||
background-color: #fff;
|
||||
border-radius: 15rpx;
|
||||
.li {
|
||||
text-align: center;
|
||||
.img-box {
|
||||
.img {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
.h4 {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
line-height: 33rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
}
|
||||
&.terminal4 {
|
||||
width: 1000rpx;
|
||||
.li {
|
||||
.img-box {
|
||||
display: inline-block;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border: 2rpx solid #f3f4f5;
|
||||
border-radius: 10rpx;
|
||||
&-inner {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
.img {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
.h4 {
|
||||
font-size: 18rpx;
|
||||
color: #ccc;
|
||||
line-height: 1em;
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
190
components/canvasShow/basics/newProduct/app/index.vue
Normal file
190
components/canvasShow/basics/newProduct/app/index.vue
Normal file
@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<div class="hom-pro-list" v-if="productData.length>0">
|
||||
<div class="product-swiper">
|
||||
<div class="product-swiper-box">
|
||||
<div class="product-swiper-warp" v-for="(item,index) in productData.slice(0, 3)" :key="index">
|
||||
<div class=" product-swiper-item" @click="jumpProductDetail(item)">
|
||||
<div class="product-swiper-img">
|
||||
<image class="img pic-img default-img" :src="item.image"/>
|
||||
</div>
|
||||
<div class="product-swiper-info">
|
||||
<label class="product-name">{{item.productName}}</label>
|
||||
<div class="price-warp">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<image class="iconImg" v-if="item.activityType == 1" src="https://ceres.zkthink.com/static/canvas-images/groupBuyIcon.png"/>
|
||||
<image class="iconImg" v-if="item.activityType == 2" src="https://ceres.zkthink.com/static/canvas-images/spikeIcon.png"/>
|
||||
<image class="iconImg" v-if="item.activityType == 4" src="https://ceres.zkthink.com/static/canvas-images/spikeIcon.png"/>
|
||||
<image class="iconImg" v-if="item.activityType == 3" src="https://ceres.zkthink.com/static/canvas-images/discountListIcon.png"/>
|
||||
<image class="iconImg" v-if="item.activityType == 5" src="https://ceres.zkthink.com/static/canvas-images/discountListIcon.png"/>
|
||||
<image class="iconImg" v-if="item.activityType == 9" src="https://ceres.zkthink.com/static/canvas-images/memberCenterIcon.png"/>
|
||||
<image class="iconImg" v-if="item.activityType == 8" src="https://zk-cereshop.oss-cn-shenzhen.aliyuncs.com/zkthink/2022-02-15/d0d8d96f28904167b271de4ae924d1a8_sceneMarketing.png"/>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP-PLUS -->
|
||||
<image class="iconImg" v-if="item.activityType == 1" src="https://ceres.zkthink.com/static/canvas-images/groupBuyIcon.png"></image>
|
||||
<image class="iconImg" v-if="item.activityType == 2" src="https://ceres.zkthink.com/static/canvas-images/spikeIcon.png"></image>
|
||||
<image class="iconImg" v-if="item.activityType == 4" src="https://ceres.zkthink.com/static/canvas-images/spikeIcon.png"></image>
|
||||
<image class="iconImg" v-if="item.activityType == 3" src="https://ceres.zkthink.com/static/canvas-images/discountListIcon.png"></image>
|
||||
<image class="iconImg" v-if="item.activityType == 5" src="https://ceres.zkthink.com/static/canvas-images/discountListIcon.png"></image>
|
||||
<image class="iconImg" v-if="item.activityType == 9" src="https://ceres.zkthink.com/static/canvas-images/memberCenterIcon.png"></image>
|
||||
<image class="iconImg" v-if="item.activityType == 8" src="https://zk-cereshop.oss-cn-shenzhen.aliyuncs.com/zkthink/2022-02-15/d0d8d96f28904167b271de4ae924d1a8_sceneMarketing.png"></image>
|
||||
<!-- #endif -->
|
||||
<div class="price">
|
||||
¥ {{item.price}}
|
||||
</div>
|
||||
<!-- <div class="original-price">-->
|
||||
<!-- ¥ {{item.originalPrice}}-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination new-pagination"></div>
|
||||
</div>
|
||||
<button v-show="componentContent.showMore" class="btn-more" @click="jumpProList(componentContent.productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
import commonMixin from '../mixin';
|
||||
const props = defineProps({
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
});
|
||||
const { componentContent } = toRefs(props);
|
||||
const { productData, jumpProductDetail, jumpProList } = commonMixin(componentContent);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hom-pro-list{
|
||||
::v-deep .swiper-wrapper{
|
||||
position: static;
|
||||
}
|
||||
/**横向滑动**/
|
||||
.product-swiper{
|
||||
width: 100%;
|
||||
height: 454upx;
|
||||
padding: 90upx 34upx 0;
|
||||
background: url("https://ceres.zkthink.com/static/canvas-images/newProduct/bg-product-card.png") no-repeat center;
|
||||
background-size: 710upx 454upx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
&+.btn-more{
|
||||
margin-top: 20upx;
|
||||
}
|
||||
.title{
|
||||
padding: 22upx 0upx 0 0;
|
||||
label{
|
||||
background-image: none;
|
||||
color: #A56C4C;
|
||||
font-style: italic;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
&-box {
|
||||
padding-bottom: 20upx;
|
||||
display: flex;
|
||||
}
|
||||
&-warp{
|
||||
padding: 0 5upx;
|
||||
}
|
||||
&-item {
|
||||
width: 220upx;
|
||||
position: relative;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
&-img {
|
||||
width: 220upx;
|
||||
height: 220upx;
|
||||
position: relative;
|
||||
&:after{
|
||||
content: '';
|
||||
display: block;
|
||||
width: 54upx;
|
||||
height: 54upx;
|
||||
background: url("https://ceres.zkthink.com/static/canvas-images/newProduct/flag-new.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
&-info {
|
||||
background-color: #FFFFFF;
|
||||
padding: 10upx;
|
||||
text-align: center;
|
||||
.product-name{
|
||||
font-size: 20upx;
|
||||
color: #333;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 6upx;
|
||||
line-height: 28upx;
|
||||
}
|
||||
.price-warp{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
line-height: 28upx;
|
||||
.iconImg {
|
||||
width: 58rpx;
|
||||
height: 36rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.price{
|
||||
color: #C83732;
|
||||
font-size: 20upx;
|
||||
margin-right: 10upx;
|
||||
}
|
||||
.original-price{
|
||||
font-size: 16upx;
|
||||
color: #ccc;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pagination{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
::v-deep .swiper-pagination-bullet{
|
||||
width: 24upx;
|
||||
height: 4upx;
|
||||
background: #FFFFFF;
|
||||
opacity: 0.5;
|
||||
border-radius: 2upx;
|
||||
margin: 0 10upx;
|
||||
}
|
||||
::v-deep .swiper-pagination-bullet-active{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.btn-more {
|
||||
width: 170upx;
|
||||
height: 54upx;
|
||||
border: 2upx solid #C5AA7B;
|
||||
color: #C5AA7B;
|
||||
font-size: 24upx;
|
||||
background-color: transparent;
|
||||
margin: 20upx auto 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
</style>
|
63
components/canvasShow/basics/newProduct/mixin.js
Normal file
63
components/canvasShow/basics/newProduct/mixin.js
Normal file
@ -0,0 +1,63 @@
|
||||
import api from '../../config/api'
|
||||
import {
|
||||
funMixin
|
||||
} from '../../config/mixin'
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
} from 'vue';
|
||||
|
||||
export default function (componentContent) {
|
||||
const {
|
||||
sendReq,
|
||||
jumpProductDetail,
|
||||
jumpProList
|
||||
} = funMixin()
|
||||
const productData = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
getData(true)
|
||||
})
|
||||
|
||||
function getData(isFirst) {
|
||||
if (componentContent.value.productData.sourceType === '1') {
|
||||
if(componentContent.value.productData.productIdList && componentContent.value.productData.productIdList.length>0){
|
||||
sendReq({
|
||||
url: `${api.getProducts}?page=1&pageSize=99&ids=${componentContent.value.productData.productIdList}`,
|
||||
method: 'GET'
|
||||
}, (proRes) => {
|
||||
productData.value = proRes.data.list
|
||||
if(isFirst){
|
||||
componentContent.value.productData.imgTextData = productData.value
|
||||
}
|
||||
// _.$forceUpdate() // 刷新轮播图
|
||||
|
||||
})
|
||||
} else {
|
||||
productData.value = []
|
||||
}
|
||||
} else if(componentContent.value.productData.sourceType === '2'){
|
||||
if(componentContent.value.productData.categoryId) {
|
||||
sendReq({
|
||||
url: `${api.getProducts}?page=1&pageSize=99&classifyId=${componentContent.value.productData.categoryId}`,
|
||||
method: 'GET'
|
||||
}, (proRes) => {
|
||||
productData.value = proRes.data.list
|
||||
if(isFirst){
|
||||
componentContent.value.productData.imgTextData = productData.value
|
||||
}
|
||||
// _.$forceUpdate() // 刷新轮播图
|
||||
})
|
||||
} else {
|
||||
productData.value = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
productData,
|
||||
jumpProductDetail,
|
||||
jumpProList
|
||||
}
|
||||
}
|
||||
|
90
components/canvasShow/basics/notice.vue
Normal file
90
components/canvasShow/basics/notice.vue
Normal file
@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div class="notice-list" :class="'terminal'+terminal" :style="{backgroundColor:componentContent.bgColor}">
|
||||
<swiper class="swiper-wrapper" :circular="true" :indicator-dots="false" :autoplay="true" :vertical="true">
|
||||
<swiper-item class="swiper-slide" v-for="(item,index) in noticesList" :key="index">
|
||||
<div class="a-link" @click="jumpNoticeDetail(item)" :style="{color:componentContent.titColor}"><span>{{item.noticeTitle}}</span></div>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from '../config/api'
|
||||
import { ref, toRefs, onMounted } from 'vue';
|
||||
import funMixin from '../config/mixin/funMixin.js'
|
||||
const { jumpNoticeDetail, sendReq, beforeGetData, afterGetData } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
|
||||
const noticesList = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
|
||||
function getData() {
|
||||
let _url = `${api.getNotices}`
|
||||
const params = {
|
||||
method: 'GET',
|
||||
url: _url,
|
||||
}
|
||||
sendReq(params, (res) => {
|
||||
noticesList.value = res.data
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notice-list{
|
||||
height: 60upx;
|
||||
line-height: 60upx;
|
||||
overflow: hidden;
|
||||
background: url("https://b2c-pro-static-dev.zkthink.com/static/images/icon-notice.png") no-repeat 20rpx center / 30upx 30upx;
|
||||
.a-link{
|
||||
// display: block;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
margin: 0 20upx;
|
||||
span{
|
||||
display: inline-block;
|
||||
padding-left: 50upx;
|
||||
font-size: 24upx;
|
||||
}
|
||||
}
|
||||
&.terminal4{
|
||||
height: 50upx;
|
||||
line-height: 50upx;
|
||||
padding: 0;
|
||||
.swiper-container{
|
||||
height: 100%;
|
||||
width: 1200upx;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.a-link{
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin: 0 20upx;
|
||||
span{
|
||||
display: block;
|
||||
padding-left: 25upx;
|
||||
font-size: 14upx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
226
components/canvasShow/basics/price/app/index.vue
Normal file
226
components/canvasShow/basics/price/app/index.vue
Normal file
@ -0,0 +1,226 @@
|
||||
<template>
|
||||
<div class="group-list" v-if="productData&&productData.composeProducts&&productData.composeProducts.length>0">
|
||||
<div class="group-warp">
|
||||
<div class="title">
|
||||
<label>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<image class="title-img" src="https://ceres.zkthink.com/static/canvas-images/price/img-title.png" alt="组合优惠" mode="widthFix"/>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP-PLUS -->
|
||||
<image class="title-img" src="https://ceres.zkthink.com/static/canvas-images/price/img-title.png" alt="组合优惠" mode="widthFix"/>
|
||||
<!-- #endif -->
|
||||
</label>
|
||||
<div class="price-text">
|
||||
<swiper class="swiper" :autoplay="true" :vertical="true">
|
||||
<swiper-item v-for="(item,index) in productData.rules" :key="index">
|
||||
{{item.price}}元任选{{item.number}}件
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</div>
|
||||
<a v-show="componentContent.showMore" class="btn-all a-link" @click="jumpCombination(productData)">更多<i class="iconfont icon-arrow-right"></i></a>
|
||||
</div>
|
||||
<div>
|
||||
<swiper class="swiper pro-box" :indicator-dots="false" :autoplay="true" :display-multiple-items="2" @change="swiperChange">
|
||||
<swiper-item class="pro-item-warp" v-for="(item,index) in productData.composeProducts" :key="index" @click="jumpProductDetail(item)">
|
||||
<div class="pro-item-inner">
|
||||
<div class="pro-item">
|
||||
<div class="pro-item-img">
|
||||
<image class="img default-img" :src="item.image"/>
|
||||
</div>
|
||||
<div class="pro-item-info">
|
||||
<h3 class="name">
|
||||
{{item.productName}}
|
||||
</h3>
|
||||
<div class="stock">
|
||||
还剩{{item.stockNumber}}件
|
||||
</div>
|
||||
<div class="price-warp">
|
||||
<div class="price">
|
||||
¥ {{item.price}}
|
||||
</div>
|
||||
<div class="original-price">
|
||||
¥ {{item.originalPrice}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="swiper-dots" v-if="productData.composeProducts && productData.composeProducts.length > 2">
|
||||
<text class="dot" :class="index - swiperCurrent <= 1 && index - swiperCurrent >=0 && 'dot-active'" v-for="(dot, index) in productData.composeProducts.length"
|
||||
:key="index"></text>
|
||||
</view>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, toRefs} from 'vue';
|
||||
import commonMixin from '../mixin';
|
||||
const props = defineProps({
|
||||
shopId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
});
|
||||
const { shopId, componentContent } = toRefs(props);
|
||||
const { productData, jumpProductDetail, jumpCombination} = commonMixin(componentContent, shopId);
|
||||
const swiperCurrent = ref(0)
|
||||
|
||||
function swiperChange(e) {
|
||||
swiperCurrent.value = e.detail.current;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.group-list{
|
||||
padding: 30upx 20upx 60upx;
|
||||
.group-warp{
|
||||
height: 544upx;
|
||||
padding: 0 10upx;
|
||||
background: #333333;
|
||||
box-shadow: 0 20upx 30upx rgba(0, 0, 0, 0.3);
|
||||
opacity: 1;
|
||||
border-radius: 20upx;
|
||||
position: relative;
|
||||
}
|
||||
.title{
|
||||
display: flex;
|
||||
align-items:center;
|
||||
position: relative;
|
||||
padding: 32upx 0 20upx 20upx;
|
||||
.title-img{
|
||||
width: 203upx;
|
||||
}
|
||||
.price-text{
|
||||
width: 300upx;
|
||||
height: 50upx;
|
||||
background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
|
||||
box-shadow: 0 6upx 12upx rgba(233, 0, 0, 0.3);
|
||||
border-radius: 26upx;
|
||||
font-size: 24upx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 50upx;
|
||||
margin-left: 20upx;
|
||||
.swiper{
|
||||
height: 50upx;
|
||||
}
|
||||
}
|
||||
.btn-all{
|
||||
position: absolute;
|
||||
right: 8upx;
|
||||
top: 40upx;
|
||||
line-height: 33upx;
|
||||
padding-right: 25upx;
|
||||
font-size: 24upx;
|
||||
color: #FFEBC4;
|
||||
.iconfont{
|
||||
content: '';
|
||||
font-size: 26upx;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.pro-box{
|
||||
padding-bottom: 20upx;
|
||||
height: 450upx;
|
||||
.pro-item-inner{
|
||||
padding: 0 10upx;
|
||||
}
|
||||
.pro-item{
|
||||
width: 100%;
|
||||
height: 412upx;
|
||||
background: #FFFFFF;
|
||||
.pro-item-img{
|
||||
.img{
|
||||
width: 100%;
|
||||
height: 236upx;
|
||||
}
|
||||
}
|
||||
.pro-item-info{
|
||||
padding: 0 20upx;
|
||||
.name{
|
||||
font-size: 24upx;
|
||||
line-height: 40upx;
|
||||
color: #333333;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.stock{
|
||||
padding: 0 8upx;
|
||||
height: 40upx;
|
||||
border: 2upx solid #E4E5E6;
|
||||
line-height: 40upx;
|
||||
margin: 10upx 0;
|
||||
display: inline-block;
|
||||
font-size: 20upx;
|
||||
color: #C5AA7B;
|
||||
}
|
||||
.price{
|
||||
font-size: 32upx;
|
||||
font-weight: bold;
|
||||
line-height: 44upx;
|
||||
color: #C83732;
|
||||
padding-right: 10upx;
|
||||
display: inline-block;
|
||||
}
|
||||
.original-price{
|
||||
font-size: 20upx;
|
||||
line-height: 28upx;
|
||||
color: #CCCCCC;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//.pagination{
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// ::v-deep .swiper-pagination-bullet{
|
||||
// width: 24upx;
|
||||
// height: 4upx;
|
||||
// background: #fff;
|
||||
// opacity: 0.5;
|
||||
// border-radius: 2upx;
|
||||
// margin: 0 5upx;
|
||||
// }
|
||||
// ::v-deep .swiper-pagination-bullet-active{
|
||||
// opacity: 1;
|
||||
// }
|
||||
//}
|
||||
.swiper-dots {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 15rpx;
|
||||
z-index: 66;
|
||||
.dot {
|
||||
width: 24upx;
|
||||
height: 4upx;
|
||||
background: #fff;
|
||||
opacity: 0.5;
|
||||
border-radius: 2upx;
|
||||
margin: 0 10upx;
|
||||
}
|
||||
|
||||
.dot-active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
54
components/canvasShow/basics/price/mixin.js
Normal file
54
components/canvasShow/basics/price/mixin.js
Normal file
@ -0,0 +1,54 @@
|
||||
import api from '../../config/api'
|
||||
import {
|
||||
funMixin
|
||||
} from '../../config/mixin'
|
||||
const { sendReq} = funMixin()
|
||||
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
} from 'vue';
|
||||
|
||||
export default function (componentContent, shopId) {
|
||||
const {
|
||||
jumpProductDetail,
|
||||
jumpCombination
|
||||
} = funMixin()
|
||||
const productData = ref({
|
||||
composeProducts: [],
|
||||
rules: [{
|
||||
price: null,
|
||||
number: null,
|
||||
}],
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getData(true)
|
||||
})
|
||||
|
||||
function getData() {
|
||||
if(componentContent.value.priceId){
|
||||
const params = {
|
||||
method: 'GET',
|
||||
url: `${api.getPrices}?shopId=${shopId.value}&ids=${componentContent.value.priceId}&page=1&pageSize=10`,
|
||||
}
|
||||
sendReq(params, (res) => {
|
||||
if( res.data.length > 0){
|
||||
productData.value = res.data[0]
|
||||
}
|
||||
})
|
||||
} else {
|
||||
productData.value = {
|
||||
composeProducts: [],
|
||||
rules: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getData,
|
||||
productData,
|
||||
jumpProductDetail,
|
||||
jumpCombination
|
||||
}
|
||||
}
|
500
components/canvasShow/basics/product/app/index.vue
Normal file
500
components/canvasShow/basics/product/app/index.vue
Normal file
@ -0,0 +1,500 @@
|
||||
<template>
|
||||
<global-loading />
|
||||
<div class="hom-pro-list">
|
||||
<div class="header">
|
||||
<div class="header-warp">
|
||||
<div class="title">商品推荐</div>
|
||||
<!-- <text class="sub-title">拼着买更划算</text>-->
|
||||
</div>
|
||||
<a
|
||||
v-show="componentContent.showMore"
|
||||
class="btn-all a-link"
|
||||
@click="jumpProList(productData)">查看更多<i class="iconfont icon-arrow-right"></i></a>
|
||||
</div>
|
||||
<div
|
||||
v-if="componentContent.arrangeType === '横向滑动' && productData.length > 2"
|
||||
class="product-list"
|
||||
>
|
||||
<swiper
|
||||
ref="mySwiper"
|
||||
class="swiper product-list-box"
|
||||
:circular="true"
|
||||
:indicator-dots="false"
|
||||
:autoplay="true"
|
||||
:display-multiple-items="2"
|
||||
@change="swiperChange"
|
||||
>
|
||||
<swiper-item
|
||||
class="product-list-item-warp"
|
||||
v-for="(item,index) in productData"
|
||||
:key="index"
|
||||
>
|
||||
<div
|
||||
class="product-list-item full-height"
|
||||
v-if="JSON.stringify(item)!=='{}'"
|
||||
@click="jumpProductDetail(item)">
|
||||
<div class="product-list-img">
|
||||
<image
|
||||
class="img pic-img default-img"
|
||||
:src="item.image"
|
||||
/>
|
||||
</div>
|
||||
<div class="product-list-info">
|
||||
<label class="product-name">{{ item.storeName }}</label>
|
||||
<div
|
||||
v-if="item.campaignType === 1"
|
||||
class="box-group">
|
||||
<div class="price">¥{{ item.price }}</div>
|
||||
<label class="group-num">{{ item.person || 0 }}人团</label>
|
||||
<div class="btn">立刻拼团</div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="[2,3].includes(item.campaignType)"
|
||||
class="box-spike">
|
||||
<div class="price">¥{{ item.campaignPrice }}</div>
|
||||
<view class="quantity-warp">
|
||||
<view class="quantity">
|
||||
限量{{ item.campaignTotal }}件
|
||||
</view>
|
||||
<uv-line-progress
|
||||
activeColor="#EE6D46"
|
||||
inactiveColor="#E6E6E6"
|
||||
height="14rpx"
|
||||
:percentage="getPercentageNum(item)"
|
||||
:showText="false"
|
||||
/>
|
||||
</view>
|
||||
<div class="btn">立即抢购</div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="box-default">
|
||||
<div class="price">¥{{ item.price }}</div>
|
||||
<div class="quantity">限量{{ item.stock }}件</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 自定义骨架屏 -->
|
||||
<div
|
||||
class="product-list-item ske-loading"
|
||||
v-else
|
||||
>
|
||||
<div class="product-list-img child-loading">
|
||||
|
||||
</div>
|
||||
<div class="product-list-info">
|
||||
<label class="product-name child-loading"></label>
|
||||
<div
|
||||
class="price-warp child-loading"
|
||||
style="padding: 5px 0">
|
||||
</div>
|
||||
<div
|
||||
class="price-warp child-loading"
|
||||
style="padding: 5px 0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view
|
||||
class="swiper-dots"
|
||||
v-if="productData && productData.length > 2"
|
||||
>
|
||||
<text
|
||||
class="dot"
|
||||
:class="index - swiperCurrent <= 1 && index - swiperCurrent >=0 && 'dot-active'"
|
||||
v-for="(dot, index) in productData.length"
|
||||
:key="index"
|
||||
></text>
|
||||
</view>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="product-list"
|
||||
>
|
||||
|
||||
<div
|
||||
class="product-list-box"
|
||||
v-if="productData.length>0">
|
||||
<div
|
||||
class="product-list-item-warp"
|
||||
v-for="(col,i) in colList"
|
||||
:key="i"
|
||||
>
|
||||
<div
|
||||
v-for="(item,index) in col.data"
|
||||
:key="index"
|
||||
@click="jumpProductDetail(item)"
|
||||
class="product-list-item"
|
||||
>
|
||||
<div class="product-list-img">
|
||||
<image
|
||||
class="img pic-img default-img"
|
||||
:src="item.image"
|
||||
/>
|
||||
</div>
|
||||
<div class="product-list-info">
|
||||
<label class="product-name">{{ item.storeName }}</label>
|
||||
<div
|
||||
v-if="item.campaignType === 1"
|
||||
class="box-group">
|
||||
<div class="price">¥{{ item.campaignPrice }}</div>
|
||||
<label class="group-num">{{ item.person || 0 }}人团</label>
|
||||
<div class="btn">立刻拼团</div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="[2,3].includes(item.campaignType)"
|
||||
class="box-spike">
|
||||
<div class="price">¥{{ item.campaignPrice }}</div>
|
||||
<view class="quantity-warp">
|
||||
<view class="quantity">
|
||||
限量{{ item.campaignTotal }}件
|
||||
</view>
|
||||
<uv-line-progress
|
||||
activeColor="#EE6D46"
|
||||
inactiveColor="#E6E6E6"
|
||||
height="14rpx"
|
||||
:percentage="getPercentageNum(item)"
|
||||
:showText="false"
|
||||
/>
|
||||
</view>
|
||||
<div class="btn">立即抢购</div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="box-default">
|
||||
<div class="price">¥{{ item.price }}</div>
|
||||
<div class="quantity">限量{{ item.stock }}件</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 自定义骨架屏 -->
|
||||
<div
|
||||
class="product-list-box"
|
||||
v-else>
|
||||
<div
|
||||
class="product-list-item-warp"
|
||||
v-for="(item,i) in loadNum"
|
||||
:key="i"
|
||||
>
|
||||
<div
|
||||
class="product-list-item ske-loading"
|
||||
>
|
||||
<div class="product-list-img child-loading"></div>
|
||||
<div class="product-list-info">
|
||||
<label class="product-name child-loading"></label>
|
||||
<div
|
||||
class="price-warp child-loading"
|
||||
style="padding: 5px 0"></div>
|
||||
<div
|
||||
class="price-warp child-loading"
|
||||
style="padding: 5px 0"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, toRefs } from 'vue';
|
||||
import productMixin from '../mixin.js';
|
||||
|
||||
const props = defineProps({
|
||||
typeId: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {typeId, componentContent} = toRefs(props);
|
||||
const {productData, jumpProductDetail, jumpProList, loadNext, getPercentageNum} = productMixin(componentContent);
|
||||
const swiperCurrent = ref(0)
|
||||
|
||||
const colList = computed(() => [
|
||||
{
|
||||
data: productData.value.filter((item, index) => index % 2 === 0)
|
||||
},
|
||||
{
|
||||
data: productData.value.filter((item, index) => index % 2 !== 0)
|
||||
}
|
||||
])
|
||||
|
||||
const loadNum = computed(() => {
|
||||
if (componentContent.value.productData.productIdList && componentContent.value.productData.productIdList.length > 0) {
|
||||
return componentContent.value.productData.productIdList.length
|
||||
} else {
|
||||
return 8
|
||||
}
|
||||
})
|
||||
|
||||
function swiperChange(e) {
|
||||
swiperCurrent.value = e.detail.current;
|
||||
}
|
||||
|
||||
// 跳转到店铺主页
|
||||
function jumpStore(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages_category_page1/store/index?storeId=${ item.shopId }`
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({loadNext})
|
||||
</script>
|
||||
|
||||
<style
|
||||
lang="scss"
|
||||
scoped
|
||||
>
|
||||
.hom-pro-list {
|
||||
padding: 0 34rpx;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 20rpx;
|
||||
|
||||
.header-warp {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
font-size: 24rpx;
|
||||
color: #EE6D46;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-all {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
padding-right: 30rpx;
|
||||
background: url("https://b2c-pro-static-dev.zkthink.com/static/images/icon-arrow.png") no-repeat right center / 20upx 20upx;
|
||||
}
|
||||
}
|
||||
|
||||
.product-list {
|
||||
position: relative;
|
||||
|
||||
&-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
|
||||
&.swiper {
|
||||
height: 500rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&.product-swiper .product-list-box {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
|
||||
&-item {
|
||||
width: 331rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-sizing: content-box;
|
||||
border-radius: 15rpx;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
&-img {
|
||||
width: 331rpx;
|
||||
height: 331rpx;
|
||||
background-color: #f5f5f5;
|
||||
|
||||
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
background-color: #FFFFFF;
|
||||
//box-shadow: 0px 0px 15px 0px rgba(52, 52, 52, 0.15);
|
||||
border-radius: 0 0 10rpx 10rpx;
|
||||
padding: 20rpx;
|
||||
|
||||
label {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.product-name {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 7rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.box-group {
|
||||
position: relative;
|
||||
|
||||
.price {
|
||||
color: #EE6D46;
|
||||
font-size: 30upx;
|
||||
line-height: 42upx;
|
||||
}
|
||||
|
||||
.group-num {
|
||||
font-size: 24rpx;
|
||||
line-height: 33rpx;
|
||||
color: #999999;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 140rpx;
|
||||
height: 50rpx;
|
||||
background: #EE6D46;
|
||||
position: absolute;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
font-size: 24rpx;
|
||||
color: #FFFFFF;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.box-spike {
|
||||
position: relative;
|
||||
|
||||
.price {
|
||||
font-size: 30rpx;
|
||||
color: #EE6D46;
|
||||
}
|
||||
|
||||
.quantity-warp {
|
||||
width: 130rpx;
|
||||
|
||||
.quantity {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
::v-deep .uv-line-progress {
|
||||
border-radius: 0;
|
||||
|
||||
&__background {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&__line {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 140rpx;
|
||||
height: 50rpx;
|
||||
background: #EE6D46;
|
||||
position: absolute;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
font-size: 24rpx;
|
||||
color: #FFFFFF;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.box-default {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.price {
|
||||
font-size: 34rpx;
|
||||
color: #EE6D46;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.swiper-dots {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.dot {
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
background: #333333;
|
||||
opacity: 0.3;
|
||||
border-radius: 5rpx;
|
||||
margin: 0 10rpx;
|
||||
}
|
||||
|
||||
.dot-active {
|
||||
width: 20rpx;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-more {
|
||||
width: 170rpx;
|
||||
height: 54rpx;
|
||||
line-height: 54rpx;
|
||||
border: 2rpx solid #C5AA7B;
|
||||
color: #C5AA7B;
|
||||
font-size: 24rpx;
|
||||
background-color: transparent;
|
||||
margin: 20rpx auto 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.child-loading {
|
||||
background: linear-gradient(90deg, #f0f2f5 25%, #e6e8eb 37%, #f0f2f5 63%);
|
||||
background-size: 400% 100%;
|
||||
animation: el-skeleton-loading 1.4s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes el-skeleton-loading {
|
||||
0% {
|
||||
background-position: 100% 50%
|
||||
}
|
||||
|
||||
to {
|
||||
background-position: 0 50%
|
||||
}
|
||||
}
|
||||
|
||||
.full-height {
|
||||
height: 100%
|
||||
}
|
||||
</style>
|
78
components/canvasShow/basics/product/mixin.js
Normal file
78
components/canvasShow/basics/product/mixin.js
Normal file
@ -0,0 +1,78 @@
|
||||
import api from '../../config/api'
|
||||
import { funMixin } from '../../config/mixin'
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
export default function (componentContent) {
|
||||
const { sendReq, beforeGetData, afterGetData, jumpProductDetail, jumpProList } = funMixin()
|
||||
|
||||
const productData = ref([])
|
||||
onMounted(() => {
|
||||
getData(true)
|
||||
})
|
||||
|
||||
function getData (isFirst) {
|
||||
if (componentContent.value.productData.sourceType === '1') {
|
||||
if (
|
||||
componentContent.value.productData.productIdList?.length > 0
|
||||
) {
|
||||
beforeGetData()
|
||||
sendReq(
|
||||
{
|
||||
url: `${api.getProducts}?page=1&isPage=2&ids=${componentContent.value.productData.productIdList}`,
|
||||
method: 'GET',
|
||||
},
|
||||
(proRes) => {
|
||||
afterGetData()
|
||||
productData.value = proRes.data.list
|
||||
if (isFirst) {
|
||||
componentContent.value.productData.imgTextData = productData.value
|
||||
}
|
||||
},
|
||||
() => {
|
||||
afterGetData()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
productData.value = []
|
||||
}
|
||||
} else if (componentContent.value.productData.sourceType === '2') {
|
||||
if (componentContent.value.productData?.categoryId) {
|
||||
beforeGetData()
|
||||
sendReq(
|
||||
{
|
||||
url: `${api.getProducts}?page=1&isPage=2&cateId=${componentContent.value.productData.categoryId}`,
|
||||
method: 'GET',
|
||||
},
|
||||
(proRes) => {
|
||||
afterGetData()
|
||||
productData.value = proRes.data.list
|
||||
if (isFirst) {
|
||||
componentContent.value.productData.imgTextData = productData.value
|
||||
}
|
||||
// _.swiper.update()
|
||||
},
|
||||
() => {
|
||||
afterGetData()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
productData.value = {
|
||||
products: [],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取进度条数字
|
||||
function getPercentageNum(item){
|
||||
const total = item.campaignTotal || item.total
|
||||
const stock = item.campaignStock || item.stock
|
||||
return (total-stock)/total
|
||||
}
|
||||
return {
|
||||
productData,
|
||||
jumpProductDetail,
|
||||
jumpProList,
|
||||
getPercentageNum
|
||||
}
|
||||
}
|
145
components/canvasShow/basics/shop.vue
Normal file
145
components/canvasShow/basics/shop.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div class="shop" :class="'terminal' + terminal">
|
||||
<swiper class="swiper" :indicator-dots="false" :autoplay="true" @change="swiperChange">
|
||||
<swiper-item class="shop-item" v-for="(item,index) in imgList" :key="index">
|
||||
<div class="shop-item-warp">
|
||||
<image class="img" :src="item.img" mode="widthFix" />
|
||||
<div class="a-link" @click="jumpLink(item.linkObj)">
|
||||
进店逛逛<i class="iconfont icon-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="swiper-dots" v-if="imgList && imgList.length">
|
||||
<text class="dot" :class="index === swiperCurrent && 'dot-active'" v-for="(dot, index) in imgList.length"
|
||||
:key="index"></text>
|
||||
</view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {toRefs, onMounted, computed, ref} from 'vue';
|
||||
import funMixin from '../config/mixin/funMixin.js'
|
||||
const { jumpLink } = funMixin()
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
const swiperCurrent = ref(0)
|
||||
|
||||
function swiperChange(e) {
|
||||
swiperCurrent.value = e.detail.current;
|
||||
}
|
||||
onMounted(() => {
|
||||
// this.$forceUpdate() // 刷新轮播图
|
||||
})
|
||||
const imgList = computed(() => {
|
||||
return componentContent.value.imgTextData.filter(function (item) {
|
||||
return item.img
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.shop{
|
||||
position: relative;
|
||||
.swiper{
|
||||
height: 460upx;
|
||||
}
|
||||
&-item{
|
||||
&-warp{
|
||||
position: relative;
|
||||
padding: 0 20upx;
|
||||
.img{
|
||||
width: 100%;
|
||||
height: 420upx;
|
||||
}
|
||||
.a-link{
|
||||
width: 220upx;
|
||||
height: 80upx;
|
||||
line-height: 80upx;
|
||||
background: linear-gradient(225deg, #585858 0%, #333333 100%);
|
||||
box-shadow: 0px 20upx 40upx rgba(0, 0, 0, 0.3);
|
||||
display: block;
|
||||
color: #fff;
|
||||
font-size: 28upx;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 30upx;
|
||||
.icon{
|
||||
margin-left: 20upx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//.pagination{
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// padding:20upx 0;
|
||||
// ::v-deep .swiper-pagination-bullet{
|
||||
// width: 12upx;
|
||||
// height: 12upx;
|
||||
// background: #333333;
|
||||
// border-radius: 50%;
|
||||
// opacity: 0.2;
|
||||
// margin: 0 10upx;
|
||||
// }
|
||||
// ::v-deep .swiper-pagination-bullet-active{
|
||||
// width: 24upx;
|
||||
// height: 12upx;
|
||||
// background: #333333;
|
||||
// opacity: 1;
|
||||
// border-radius: 8upx;
|
||||
// }
|
||||
//}
|
||||
//::v-deep .uni-swiper-dots{
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// padding: 0upx 0;
|
||||
// .uni-swiper-dot{
|
||||
// width: 10upx;
|
||||
// height: 10upx;
|
||||
// background: #333333;
|
||||
// opacity: 0.3;
|
||||
// border-radius: 5upx;
|
||||
// margin: 0 5upx;
|
||||
// &-active{
|
||||
// width: 20upx;
|
||||
// height: 10upx;
|
||||
// opacity: 1;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
.swiper-dots {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 15rpx;
|
||||
z-index: 66;
|
||||
.dot {
|
||||
width: 10upx;
|
||||
height: 10upx;
|
||||
background: #333333;
|
||||
opacity: 0.3;
|
||||
border-radius: 5upx;
|
||||
margin: 0 10upx;
|
||||
}
|
||||
|
||||
.dot-active {
|
||||
width: 20upx;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
171
components/canvasShow/basics/spike/app/index.vue
Normal file
171
components/canvasShow/basics/spike/app/index.vue
Normal file
@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div class="spike">
|
||||
<div class="spike-card" v-if="productList?.length>0">
|
||||
<div class="spike-card-top">
|
||||
<h2 class="spike-card-top-title">
|
||||
限时秒杀
|
||||
</h2>
|
||||
<div class="spike-card-top-time" v-if="activityData?.state===2">
|
||||
<div class="session">活动已结束</div>
|
||||
</div>
|
||||
<div class="spike-card-top-time" v-else-if="count?.length > 0">
|
||||
<div class="session">距活动{{count[0]}}还有</div>
|
||||
<div class="time">{{count[1]}}:{{count[2]}}:{{count[3]}}</div>
|
||||
</div>
|
||||
<a v-show="componentContent.showMore" class="btn-more" @click="jumpSeckills(componentContent.id)">查看更多</a>
|
||||
</div>
|
||||
<div class="spike-card-list">
|
||||
<div class="spike-card-item" v-for='item in productList.slice(0,4)' :key='item.productId' @click="jumpProductDetail(item)">
|
||||
<div class="spike-card-item-img">
|
||||
<image :src="item.image" alt="" />
|
||||
</div>
|
||||
<div class="spike-card-item-info">
|
||||
<h3 class="name">
|
||||
{{item.storeName}}
|
||||
</h3>
|
||||
<div class="price-warp">
|
||||
<div class="price">¥{{item.price}}</div>
|
||||
<!-- <div class="original-price">
|
||||
¥ {{item.originalPrice}}
|
||||
</div> -->
|
||||
<div class="stock">
|
||||
限量{{item.stock}}件
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import commonMixin from '../mixin'
|
||||
import { toRefs } from 'vue';
|
||||
const props = defineProps({
|
||||
typeId: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
shopId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { typeId, shopId, componentContent } = toRefs(props)
|
||||
const { activityData, productList, count, jumpProductDetail, jumpSeckills } = commonMixin(componentContent, typeId, shopId)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.spike{
|
||||
&-card{
|
||||
border-radius: 20rpx;
|
||||
margin: 0 34rpx;
|
||||
&-top{
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 17rpx;
|
||||
&-title{
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-right: 25rpx;
|
||||
font-weight: normal;
|
||||
}
|
||||
&-time{
|
||||
height: 40rpx;
|
||||
border-radius: 21rpx;
|
||||
border: 1rpx solid #EE6D46;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
.session{
|
||||
height: 100%;
|
||||
line-height: 40rpx;
|
||||
background: #EE6D46;
|
||||
font-size: 20rpx;
|
||||
color: #FFFFFF;
|
||||
padding: 0 15rpx;
|
||||
border-radius: 21rpx;
|
||||
}
|
||||
.time{
|
||||
font-size: 20rpx;
|
||||
color: #EE6D46;
|
||||
padding: 0 14rpx 0 10rpx;
|
||||
}
|
||||
}
|
||||
.btn-more{
|
||||
position: absolute;
|
||||
right: 8rpx;
|
||||
top: 0rpx;
|
||||
line-height: 40rpx;
|
||||
padding-right: 30rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
background: url("https://b2c-pro-static-dev.zkthink.com/static/images/icon-arrow.png") no-repeat right center / 20rpx 20rpx;
|
||||
}
|
||||
}
|
||||
&-list{
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
padding: 20rpx;
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
&-item{
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
flex: 0 0 203rpx;
|
||||
margin-right: 18rpx;
|
||||
&-img{
|
||||
width: 203rpx;
|
||||
height: 203rpx;
|
||||
image{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
&-info{
|
||||
width: 203rpx;
|
||||
.name{
|
||||
font-size: 30rpx;
|
||||
font-weight: normal;
|
||||
line-height: 40rpx;
|
||||
color: #333333;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
padding: 15rpx 0 6rpx;
|
||||
}
|
||||
.price-warp{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.price{
|
||||
font-size: 32rpx;
|
||||
color: #EE6D46;
|
||||
padding-right: 10rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
.original-price{
|
||||
font-size: 20rpx;
|
||||
line-height: 28rpx;
|
||||
color: #CCCCCC;
|
||||
display: inline-block;
|
||||
}
|
||||
.stock{
|
||||
line-height: 1em;
|
||||
display: inline-block;
|
||||
font-size: 20rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
102
components/canvasShow/basics/spike/mixin.js
Normal file
102
components/canvasShow/basics/spike/mixin.js
Normal file
@ -0,0 +1,102 @@
|
||||
import api from '../../config/api'
|
||||
import { funMixin } from '../../config/mixin'
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
export default function (componentContent, typeId, shopId) {
|
||||
const { sendReq, beforeGetData, afterGetData, jumpProductDetail, jumpSeckills } = funMixin()
|
||||
const activityData = ref({})
|
||||
const productList = ref([])
|
||||
const count = ref([])
|
||||
const timer = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
if (componentContent.value.id) {
|
||||
getProList()
|
||||
getActivit()
|
||||
} else {
|
||||
productList.value = []
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(timer.value)
|
||||
})
|
||||
|
||||
function getProList () {
|
||||
beforeGetData()
|
||||
const params = {
|
||||
method: 'POST',
|
||||
url: api.getActivityProduct,
|
||||
data: {
|
||||
isPage: 2,
|
||||
ids: [componentContent.value.id]
|
||||
}
|
||||
}
|
||||
sendReq(
|
||||
params,
|
||||
(res) => {
|
||||
afterGetData()
|
||||
productList.value = res.data.list
|
||||
},
|
||||
() => {
|
||||
afterGetData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function getActivit () {
|
||||
beforeGetData()
|
||||
const params = {
|
||||
method: 'GET',
|
||||
url: `${api.getActivity}?id=${componentContent.value.id}`,
|
||||
}
|
||||
sendReq(
|
||||
params,
|
||||
(res) => {
|
||||
afterGetData()
|
||||
activityData.value = res.data
|
||||
getTime()
|
||||
},
|
||||
() => {
|
||||
afterGetData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function getTime () {
|
||||
const date = new Date().getTime()
|
||||
let startTime = activityData.value.startTime
|
||||
let endTime = activityData.value.endTime
|
||||
let time = 0
|
||||
if (activityData.value.state === 0) {
|
||||
time = startTime - date // 未开始
|
||||
} else if(activityData.value.state === 1) {
|
||||
time = endTime - date // 进行中
|
||||
}
|
||||
let countDownInterval = setInterval(()=>{
|
||||
countDown(time)
|
||||
time -= 1000
|
||||
if(time <= 0){
|
||||
clearInterval(countDownInterval)
|
||||
activityData.value.state ++
|
||||
}
|
||||
},1000)
|
||||
}
|
||||
function countDown (time) {
|
||||
const fn = (v) => (v < 10 ? `0${v}` : v)
|
||||
const t = parseInt(time / 1000)
|
||||
const text = activityData.value.state === 0 ? '开始' : '结束'
|
||||
const hour = parseInt(t / 3600)
|
||||
const min = parseInt((t % 3600) / 60)
|
||||
const s = t % 60
|
||||
count.value = [text, fn(hour), fn(min), fn(s)]
|
||||
}
|
||||
|
||||
return {
|
||||
activityData,
|
||||
productList,
|
||||
count,
|
||||
jumpProductDetail,
|
||||
jumpSeckills
|
||||
}
|
||||
}
|
76
components/canvasShow/basics/text.vue
Normal file
76
components/canvasShow/basics/text.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div class="text warp" :class="['text-'+componentContent.textPos,{'show-more':componentContent.showMore},'terminal' + terminal]" :style="{backgroundColor:componentContent.bgColor}">
|
||||
<div class="line-warp" :class="{'borderBot':componentContent.showLine}">
|
||||
<h3 class="h3" :style="{fontSize:componentContent.fontSizeNum+'rpx',fontWeight:componentContent.textFontW,color:componentContent.titColor}">{{componentContent.title}}</h3>
|
||||
<p class="p" :style="{fontSize:componentContent.describeSizeNum+'rpx',fontWeight:componentContent.describeFontW,color:componentContent.describeColor}">{{componentContent.describe}}</p>
|
||||
<div class="btn-more" v-show="componentContent.showMore" :class="'style'+componentContent.styleValue" @click="jumpLink(item.linkObj)"><span>查看更多</span><i class="iconfont icon-arrow-right"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs } from 'vue';
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text{
|
||||
position: relative;
|
||||
.line-warp{
|
||||
padding: 10upx 0;
|
||||
}
|
||||
.borderBot{
|
||||
border-bottom: 1upx solid #cccc;
|
||||
}
|
||||
.h3{
|
||||
line-height: 1.5;
|
||||
}
|
||||
.p{
|
||||
line-height: 1.5;
|
||||
margin-top: 5upx;
|
||||
}
|
||||
.style1{
|
||||
|
||||
}
|
||||
.style2{
|
||||
.iconfont{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.style3{
|
||||
span{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.text-left{
|
||||
text-align: left;
|
||||
&.show-more{
|
||||
position: relative;
|
||||
padding-right: 20upx;
|
||||
.btn-more{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 10upx;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.text-center{
|
||||
text-align: center;
|
||||
}
|
||||
&.text-right{
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
97
components/canvasShow/basics/video.vue
Normal file
97
components/canvasShow/basics/video.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div class="videoBox" :class="'terminal' + terminal">
|
||||
<div class="videoLeftBox">
|
||||
<h3 v-if="componentContent.title">{{componentContent.title}}</h3>
|
||||
<div class="content" v-if="removeTags(componentContent.mainBody)" v-html="componentContent.mainBody"></div>
|
||||
</div>
|
||||
<div class="videoRightBox">
|
||||
<video class="myVideo" id="myVideo" :poster="componentContent.coverImg" :src="componentContent.videoUrl" enable-danmu danmu-btn controls></video>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs, ref, onMounted } from 'vue';
|
||||
const props = defineProps({
|
||||
terminal: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
})
|
||||
const { terminal, componentContent } = toRefs(props)
|
||||
const isPlay = ref(false)
|
||||
const videoContext = ref(null)
|
||||
|
||||
onMounted(()=>{
|
||||
videoContext.value = uni.createVideoContext('myVideo',this)
|
||||
})
|
||||
|
||||
function handlePlayVideo(){
|
||||
isPlay.value = true
|
||||
setTimeout(()=>{
|
||||
videoContext.value.play()
|
||||
},500)
|
||||
}
|
||||
|
||||
// 清除html标签
|
||||
const removeTags = (html)=>{
|
||||
return html.replace(/<[^>]*>/g, '');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.videoBox {
|
||||
margin: 0 35rpx;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.videoLeftBox {
|
||||
h3 {
|
||||
font-size: 28upx;
|
||||
color: #333333;
|
||||
margin-bottom: 10upx;
|
||||
font-weight: normal;
|
||||
}
|
||||
p {
|
||||
color: #333333;
|
||||
font-size: 14upx;
|
||||
line-height: 30upx;
|
||||
}
|
||||
}
|
||||
.videoRightBox {
|
||||
width: 50%;
|
||||
video {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
.terminal1,.terminal2,.terminal3{
|
||||
&.videoBox{
|
||||
display: block;
|
||||
.videoLeftBox{
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
.content{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
.videoRightBox {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.myVideo{
|
||||
aspect-ratio: 16/9;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
323
components/canvasShow/basics/vip/app/index.vue
Normal file
323
components/canvasShow/basics/vip/app/index.vue
Normal file
@ -0,0 +1,323 @@
|
||||
<template>
|
||||
<div class="vip" v-if="productData.length >0">
|
||||
<div class="vip-card">
|
||||
<div class="vip-title">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<image class="title-img" src="https://ceres.zkthink.com/static/canvas-images/vip/img-title.png" alt="会员专区" mode="widthFix"/>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP-PLUS -->
|
||||
<image class="title-img" src="https://ceres.zkthink.com/static/canvas-images/vip/img-title.png" alt="会员专区" mode="widthFix"/>
|
||||
<!-- #endif -->
|
||||
<a v-show="componentContent.showMore" class="btn-more a-link" @click="jumpVip">更多<i class="iconfont icon-arrow-right"></i></a>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="productData.length > 2">
|
||||
<swiper class="swiper vip-list" :circular="true" :indicator-dots="false" :autoplay="true" @change="swiperChange">
|
||||
<swiper-item class="vip-item-warp" v-for="(itemJ,indexJ) in listTemp" :key="indexJ">
|
||||
<div class="vip-item" v-for="(item,index) in itemJ" :key="index" @click="jumpProductDetail(item)">
|
||||
<div class="vip-item-img">
|
||||
<image class="img default-img" :src="item.image"></image>
|
||||
</div>
|
||||
<div class="vip-item-info">
|
||||
<h3 class="name">
|
||||
{{item.productName}}
|
||||
</h3>
|
||||
<div class="stock">
|
||||
还剩{{item.stockNumber}}件
|
||||
</div>
|
||||
<div class="original-price">
|
||||
¥ {{item.originalPrice}}
|
||||
</div>
|
||||
<div class="price-warp">
|
||||
<div class="flag">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<image src="https://ceres.zkthink.com/static/canvas-images/vip/flag-vip.png" alt="会员价" class="flagImg"/>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP-PLUS -->
|
||||
<image class="flagImg" src="https://ceres.zkthink.com/static/canvas-images/vip/flag-vip.png" alt="会员专区" mode="widthFix"/>
|
||||
<!-- #endif -->
|
||||
</div>
|
||||
<div class="price">
|
||||
¥ {{item.price}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-buy">
|
||||
<span>去购买</span>
|
||||
<div class="progress">
|
||||
<i></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="swiper-dots" v-if="listTemp && listTemp.length > 1">
|
||||
<text class="dot" :class="swiperCurrent === index && 'dot-active'" v-for="(dot, index) in listTemp.length"
|
||||
:key="index"></text>
|
||||
</view>
|
||||
</div>
|
||||
<div class="swiper vip-list" v-else>
|
||||
{{ productData.length }}
|
||||
|
||||
<div class="vip-item-warp" v-for="(itemJ,indexJ) in listTemp" :key="indexJ">
|
||||
<div class="vip-item" v-for="(item,index) in itemJ" :key="index" @click="jumpProductDetail(item)">
|
||||
<div class="vip-item-img">
|
||||
<image class="img default-img" :src="item.image" />
|
||||
</div>
|
||||
<div class="vip-item-info">
|
||||
<h3 class="name">
|
||||
{{item.productName}}
|
||||
</h3>
|
||||
<div class="stock">
|
||||
还剩{{item.stockNumber}}件
|
||||
</div>
|
||||
<div class="original-price">
|
||||
¥ {{item.originalPrice}}
|
||||
</div>
|
||||
<div class="price-warp">
|
||||
<div class="flag">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<image src="https://ceres.zkthink.com/static/canvas-images/vip/flag-vip.png" alt="会员价" class="flagImg"/>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP-PLUS -->
|
||||
<image class="flagImg" src="https://ceres.zkthink.com/static/canvas-images/vip/flag-vip.png" alt="会员专区" mode="widthFix"/>
|
||||
<!-- #endif -->
|
||||
</div>
|
||||
<div class="price">
|
||||
¥ {{item.price}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-buy">
|
||||
<span>去购买</span>
|
||||
<div class="progress">
|
||||
<i></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="pagination vip-pagination"></div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, toRefs } from 'vue';
|
||||
import vipMixin from '../mixin'
|
||||
const { productData, jumpVip, jumpProductDetail } = vipMixin()
|
||||
const props = defineProps({
|
||||
componentContent: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
const { componentContent } = toRefs(props)
|
||||
const swiperCurrent = ref(0)
|
||||
|
||||
function swiperChange(e) {
|
||||
swiperCurrent.value = e.detail.current;
|
||||
}
|
||||
|
||||
const listTemp = computed(() => {
|
||||
var list = productData.value
|
||||
var arrTemp = []
|
||||
var index = -1
|
||||
var count = 2 // 每组多少条
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (i % count === 0) {
|
||||
arrTemp.push([])
|
||||
index++
|
||||
}
|
||||
arrTemp[index].push(list[i])
|
||||
}
|
||||
return arrTemp
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vip{
|
||||
&-card{
|
||||
background: #333333;
|
||||
padding: 0 20upx 20upx;
|
||||
position: relative;
|
||||
}
|
||||
&-title{
|
||||
padding: 42upx 0 28upx 30upx;
|
||||
position: relative;
|
||||
.title-img{
|
||||
display: block;
|
||||
width: 197upx;
|
||||
}
|
||||
.btn-more{
|
||||
position: absolute;
|
||||
right: 8upx;
|
||||
top: 40upx;
|
||||
line-height: 33upx;
|
||||
padding-right: 25upx;
|
||||
font-size: 24upx;
|
||||
color: #FFEBC4;
|
||||
.iconfont{
|
||||
content: '';
|
||||
font-size: 26upx;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-list{
|
||||
height: 562upx;
|
||||
}
|
||||
&-item{
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
margin-top: 20upx;
|
||||
&:first-child{
|
||||
margin-top: 0upx;
|
||||
}
|
||||
&-img{
|
||||
width: 260upx;
|
||||
height: 260upx;
|
||||
margin-right: 20upx;
|
||||
background-color: #ececec;
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&-info{
|
||||
flex: 1;
|
||||
position: relative;
|
||||
.name{
|
||||
font-size: 28upx;
|
||||
//height: 75rpx;
|
||||
line-height: 40upx;
|
||||
color: #333333;
|
||||
margin: 30upx 0 10upx;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
display:-webkit-box;
|
||||
-webkit-box-orient:vertical;
|
||||
-webkit-line-clamp:1;
|
||||
}
|
||||
// #ifdef H5 || APP-PLUS
|
||||
.name{
|
||||
height: 40rpx;
|
||||
}
|
||||
// #endif
|
||||
.stock{
|
||||
color: #C5AA7B;
|
||||
font-size: 20upx;
|
||||
border: 2upx solid #E4E5E6;
|
||||
line-height: 40upx;
|
||||
padding: 0 5upx;
|
||||
display: inline-block;
|
||||
margin-bottom: 30upx;
|
||||
}
|
||||
.original-price{
|
||||
font-size: 24upx;
|
||||
line-height: 34upx;
|
||||
color: #CCCCCC;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.flag{
|
||||
float: left;
|
||||
padding: 12upx 10upx 0 0;
|
||||
.flagImg {
|
||||
width: 58upx;
|
||||
height: 36upx;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.price{
|
||||
font-size: 40upx;
|
||||
font-weight: bold;
|
||||
line-height: 56upx;
|
||||
color: #C83732;
|
||||
}
|
||||
.btn-buy{
|
||||
position: absolute;
|
||||
right: 20upx;
|
||||
bottom: 20upx;
|
||||
width: 160upx;
|
||||
height: 84upx;
|
||||
background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
|
||||
box-shadow: 0px 6upx 12upx rgba(233, 0, 0, 0.3);
|
||||
border-radius: 10upx;
|
||||
text-align: center;
|
||||
padding: 16upx 20upx 0;
|
||||
span{
|
||||
font-size: 24upx;
|
||||
line-height: 34upx;
|
||||
color: #FFFFFF;
|
||||
margin-bottom: 10upx;
|
||||
display: block;
|
||||
}
|
||||
.progress{
|
||||
height: 8upx;
|
||||
background: rgba(255,255,255,0.5);
|
||||
border-radius: 4upx;
|
||||
position: relative;
|
||||
i{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 50%;
|
||||
height: 8upx;
|
||||
background-color: #fff;
|
||||
border-radius: 4upx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.vip-item-info {
|
||||
.price-warp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.swiper-dots {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 15upx;
|
||||
z-index: 66;
|
||||
.dot {
|
||||
width: 24upx;
|
||||
height: 4upx;
|
||||
background: #fff;
|
||||
opacity: 0.5;
|
||||
border-radius: 2upx;
|
||||
margin: 0 10upx;
|
||||
}
|
||||
|
||||
.dot-active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
//.pagination{
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// padding-top:20upx;
|
||||
// ::v-deep .swiper-pagination-bullet{
|
||||
// width: 24upx;
|
||||
// height: 4upx;
|
||||
// background: #fff;
|
||||
// opacity: 0.5;
|
||||
// border-radius: 2upx;
|
||||
// margin: 0 5upx;
|
||||
// }
|
||||
// ::v-deep .swiper-pagination-bullet-active{
|
||||
// opacity: 1;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
</style>
|
29
components/canvasShow/basics/vip/mixin.js
Normal file
29
components/canvasShow/basics/vip/mixin.js
Normal file
@ -0,0 +1,29 @@
|
||||
import api from '../../config/api'
|
||||
import { funMixin } from '../../config/mixin'
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
const vipMixin = () => {
|
||||
const { sendReq, jumpVip, jumpProductDetail } = funMixin()
|
||||
const productData = ref([])
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
|
||||
function getData() {
|
||||
sendReq({
|
||||
url: `${api.getMemberProducts}?page=1&pageSize=20`,
|
||||
method: 'GET'
|
||||
}, (proRes) => {
|
||||
productData.value = proRes.data.list
|
||||
console.log(productData.value)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
productData,
|
||||
jumpVip,
|
||||
jumpProductDetail
|
||||
}
|
||||
}
|
||||
|
||||
export default vipMixin
|
103
components/canvasShow/canvasShowPage.vue
Normal file
103
components/canvasShow/canvasShowPage.vue
Normal file
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<div class="layout hom-layout">
|
||||
<div class="list-group-item"
|
||||
v-for="(item,index) in componentsData"
|
||||
:key="index">
|
||||
<!-- <component :is="componentMap[terminal-1].get(item.type)" :componentContent="item.componentContent" :terminal="terminal" :typeId="typeId" :shopId="shopId"></component>-->
|
||||
<com-header v-if="item.type==='header'" :componentContent="item.componentContent" :terminal="terminal"></com-header>
|
||||
<com-banner v-if="item.type==='banner'" :componentContent="item.componentContent" :terminal="terminal"></com-banner>
|
||||
<com-text v-if="item.type==='text'" :componentContent="item.componentContent" :terminal="terminal"></com-text>
|
||||
<com-image-text v-if="item.type==='imageText'" :componentContent="item.componentContent" :terminal="terminal"></com-image-text>
|
||||
<com-brand-list v-if="item.type==='brandList'" :componentContent="item.componentContent" :terminal="terminal"></com-brand-list>
|
||||
<com-category-list v-if="item.type==='categoryList'" :componentContent="item.componentContent" :terminal="terminal"></com-category-list>
|
||||
<com-image-text-list v-if="item.type==='imageTextList'" :componentContent="item.componentContent" :terminal="terminal"></com-image-text-list>
|
||||
<com-assist-div v-if="item.type==='assistDiv'" :componentContent="item.componentContent" :terminal="terminal"></com-assist-div>
|
||||
<com-image-text-nav v-if="item.type==='imageTextNav'" :componentContent="item.componentContent" :terminal="terminal"></com-image-text-nav>
|
||||
<com-product v-if="item.type==='productList'" :componentContent="item.componentContent" :terminal="terminal"></com-product>
|
||||
<com-video-box v-if="item.type==='videoBox'" :componentContent="item.componentContent" :terminal="terminal"></com-video-box>
|
||||
<com-coupon v-if="item.type==='coupon'" :componentContent="item.componentContent" :terminal="terminal"></com-coupon>
|
||||
<com-custom v-if="item.type==='custom'" :componentContent="item.componentContent" :terminal="terminal"></com-custom>
|
||||
<com-notice v-if="item.type==='notice'" :componentContent="item.componentContent" :terminal="terminal"></com-notice>
|
||||
<com-vip v-if="item.type==='vip'" :componentContent="item.componentContent" :terminal="terminal"></com-vip>
|
||||
<com-group v-if="item.type==='groupList'" :terminal="terminal" :componentContent="item.componentContent"></com-group>
|
||||
<com-discount v-if="item.type==='discountList'" :componentContent="item.componentContent" :terminal="terminal"></com-discount>
|
||||
<com-spike v-if="item.type==='spikeList'" :componentContent="item.componentContent" :terminal="terminal"></com-spike>
|
||||
<com-price v-if="item.type==='priceList'" :terminal="terminal"></com-price>
|
||||
<com-new-product v-if="item.type==='newProduct'" :componentContent="item.componentContent" :terminal="terminal"></com-new-product>
|
||||
<com-shop v-if="item.type==='shop'" :componentContent="item.componentContent" :terminal="terminal"></com-shop>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import comHeader from '@/components/canvasShow/basics/header/app/index.vue'
|
||||
import comBanner from '@/components/canvasShow/basics/banner.vue'
|
||||
import comText from '@/components/canvasShow/basics/text.vue'
|
||||
import comImageText from '@/components/canvasShow/basics/imageText.vue'
|
||||
import comBrandList from '@/components/canvasShow/basics/brandList.vue'
|
||||
import comCategoryList from '@/components/canvasShow/basics/categoryList.vue'
|
||||
import comImageTextList from '@/components/canvasShow/basics/imageTextList.vue'
|
||||
import comAssistDiv from '@/components/canvasShow/basics/assistDiv.vue'
|
||||
import comImageTextNav from '@/components/canvasShow/basics/imageTextNav.vue'
|
||||
import comProduct from '@/components/canvasShow/basics/product/app/index.vue'
|
||||
import comVideoBox from '@/components/canvasShow/basics/video.vue'
|
||||
import comCoupon from '@/components/canvasShow/basics/coupon/index.vue'
|
||||
import comCustom from '@/components/canvasShow/basics/custom.vue'
|
||||
import comNotice from '@/components/canvasShow/basics/notice.vue'
|
||||
import comVip from '@/components/canvasShow/basics/vip/app/index.vue'
|
||||
import comGroup from '@/components/canvasShow/basics/group/app/index.vue'
|
||||
import comDiscount from '@/components/canvasShow/basics/discount/app/index.vue'
|
||||
import comSpike from '@/components/canvasShow/basics/spike/app/index.vue'
|
||||
import comPrice from '@/components/canvasShow/basics/price/app/index.vue'
|
||||
import comNewProduct from '@/components/canvasShow/basics/newProduct/app/index.vue'
|
||||
import comShop from '@/components/canvasShow/basics/shop.vue'
|
||||
import config from '@/components/canvasShow/config/config'
|
||||
import sendReqMixin from './config/mixin/sendReqMixin'
|
||||
import { ref } from 'vue';
|
||||
import api from "@/components/canvasShow/config/api";
|
||||
const terminal = ref(config.terminal)
|
||||
const { sendReq } = sendReqMixin()
|
||||
const componentsData = ref([])
|
||||
|
||||
const getCanvasData = ()=>{
|
||||
const params = {
|
||||
method: 'GET',
|
||||
url: `${api.getCanvas}?terminal=${terminal.value}`,
|
||||
}
|
||||
sendReq(params, (res) => {
|
||||
if (res.data.json) {
|
||||
componentsData.value = JSON.parse(res.data.json)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
getCanvasData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss"
|
||||
scoped>
|
||||
.hom-layout {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.warp {
|
||||
width: 680upx;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
|
||||
&.terminal4 {
|
||||
width: 1200px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-box {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
102
components/canvasShow/componentMap.js
Normal file
102
components/canvasShow/componentMap.js
Normal file
@ -0,0 +1,102 @@
|
||||
export const componentMap = [
|
||||
// 小程序
|
||||
new Map([
|
||||
['header', () => import('./basics/header/app/index.vue')], // 首页头部
|
||||
['banner', () => import('./basics/banner.vue')], // 轮播图
|
||||
['text', () => import('./basics/text.vue')], // 文本
|
||||
['imageText', () => import('./basics/imageText.vue')], // 图文
|
||||
['brandList', () => import('./basics/brandList.vue')], // 品牌列表
|
||||
['categoryList', () => import('./basics/categoryList.vue')], // 品牌列表
|
||||
['imageTextList', () => import('./basics/imageTextList.vue')], // 图文列表
|
||||
['assistDiv', () => import('./basics/assistDiv.vue')], // 铺助分割
|
||||
['imageTextNav', () => import('./basics/imageTextNav.vue')], // 图文导航
|
||||
['productList', () => import('./basics/product/app/index.vue')], // 商品列表
|
||||
['videoBox', () => import('./basics/video.vue')], // 视频
|
||||
['coupon', () => import('./basics/coupon/index.vue')], // 优惠券
|
||||
['custom', () => import('./basics/custom.vue')], // 自定义
|
||||
['notice', () => import('./basics/notice.vue')], // 公告
|
||||
['vip', () => import('./basics/vip/app/index.vue')], // 会员专区
|
||||
['groupList', () => import('./basics/group/app/index.vue')], // 拼团专区
|
||||
['spikeList', () => import('./basics/spike/app/index.vue')], // 秒杀专区
|
||||
['priceList', () => import('./basics/price/app/index.vue')], // 定价捆绑
|
||||
['discountList', () => import('./basics/discount/app/index.vue')], // 限时折扣
|
||||
['newProduct', () => import('./basics/newProduct/app/index.vue')], // 每日上新
|
||||
['live', () => import('./basics/live/app/index.vue')], // 直播
|
||||
['shop', () => import('./basics/shop.vue')], // 每日好店
|
||||
]),
|
||||
// H5
|
||||
new Map([
|
||||
['header', () => import('./basics/header/app/index.vue')], // 首页头部
|
||||
['banner', () => import('./basics/banner.vue')], // 轮播图
|
||||
['text', () => import('./basics/text.vue')], // 文本
|
||||
['imageText', () => import('./basics/imageText.vue')], // 图文
|
||||
['brandList', () => import('./basics/brandList.vue')], // 品牌列表
|
||||
['categoryList', () => import('./basics/categoryList.vue')], // 品牌列表
|
||||
['imageTextList', () => import('./basics/imageTextList.vue')], // 图文列表
|
||||
['assistDiv', () => import('./basics/assistDiv.vue')], // 铺助分割
|
||||
['imageTextNav', () => import('./basics/imageTextNav.vue')], // 图文导航
|
||||
['productList', () => import('./basics/product/app/index.vue')], // 商品列表
|
||||
['videoBox', () => import('./basics/video.vue')], // 视频
|
||||
['coupon', () => import('./basics/coupon/app/index.vue')], // 优惠券
|
||||
['custom', () => import('./basics/custom.vue')], // 自定义
|
||||
['notice', () => import('./basics/notice.vue')], // 公告
|
||||
['vip', () => import('./basics/vip/app/index.vue')], // 会员专区
|
||||
['groupList', () => import('./basics/group/app/index.vue')], // 拼团专区
|
||||
['spikeList', () => import('./basics/spike/app/index.vue')], // 秒杀专区
|
||||
['priceList', () => import('./basics/price/app/index.vue')], // 定价捆绑
|
||||
['discountList', () => import('./basics/discount/app/index.vue')], // 限时折扣
|
||||
['newProduct', () => import('./basics/newProduct/app/index.vue')], // 每日上新
|
||||
['live', () => import('./basics/live/app/index.vue')], // 直播
|
||||
['shop', () => import('./basics/shop.vue')], // 每日好店
|
||||
]),
|
||||
// APP
|
||||
new Map([
|
||||
['header', () => import('./basics/header/app/index.vue')], // 首页头部
|
||||
['banner', () => import('./basics/banner.vue')], // 轮播图
|
||||
['text', () => import('./basics/text.vue')], // 文本
|
||||
['imageText', () => import('./basics/imageText.vue')], // 图文
|
||||
['brandList', () => import('./basics/brandList.vue')], // 品牌列表
|
||||
['categoryList', () => import('./basics/categoryList.vue')], // 品牌列表
|
||||
['imageTextList', () => import('./basics/imageTextList.vue')], // 图文列表
|
||||
['assistDiv', () => import('./basics/assistDiv.vue')], // 铺助分割
|
||||
['imageTextNav', () => import('./basics/imageTextNav.vue')], // 图文导航
|
||||
['productList', () => import('./basics/product/app/index.vue')], // 商品列表
|
||||
['videoBox', () => import('./basics/video.vue')], // 视频
|
||||
['coupon', () => import('./basics/coupon/app/index.vue')], // 优惠券
|
||||
['custom', () => import('./basics/custom.vue')], // 自定义
|
||||
['notice', () => import('./basics/notice.vue')], // 公告
|
||||
['vip', () => import('./basics/vip/app/index.vue')], // 会员专区
|
||||
['groupList', () => import('./basics/group/app/index.vue')], // 拼团专区
|
||||
['spikeList', () => import('./basics/spike/app/index.vue')], // 秒杀专区
|
||||
['priceList', () => import('./basics/price/app/index.vue')], // 定价捆绑
|
||||
['discountList', () => import('./basics/discount/app/index.vue')], // 限时折扣
|
||||
['newProduct', () => import('./basics/newProduct/app/index.vue')], // 每日上新
|
||||
['live', () => import('./basics/live/app/index.vue')], // 直播
|
||||
['shop', () => import('./basics/shop.vue')], // 每日好店
|
||||
]),
|
||||
// PC
|
||||
new Map([
|
||||
['header', () => import('./basics/header/pc/index.vue')], // 首页头部
|
||||
['banner', () => import('./basics/banner.vue')], // 轮播图
|
||||
['text', () => import('./basics/text.vue')], // 文本
|
||||
['imageText', () => import('./basics/imageText.vue')], // 图文
|
||||
['brandList', () => import('./basics/brandList.vue')], // 品牌列表
|
||||
['categoryList', () => import('./basics/categoryList.vue')], // 品牌列表
|
||||
['imageTextList', () => import('./basics/imageTextList.vue')], // 图文列表
|
||||
['assistDiv', () => import('./basics/assistDiv.vue')], // 铺助分割
|
||||
['imageTextNav', () => import('./basics/imageTextNav.vue')], // 图文导航
|
||||
['productList', () => import('./basics/product/pc/index.vue')], // 商品列表
|
||||
['videoBox', () => import('./basics/video.vue')], // 视频
|
||||
['coupon', () => import('./basics/coupon/pc/index.vue')], // 优惠券
|
||||
['custom', () => import('./basics/custom.vue')], // 自定义
|
||||
['notice', () => import('./basics/notice.vue')], // 公告
|
||||
['vip', () => import('./basics/vip/pc/index.vue')], // 会员专区
|
||||
['groupList', () => import('./basics/group/pc/index.vue')], // 拼团专区
|
||||
['spikeList', () => import('./basics/spike/pc/index.vue')], // 秒杀专区
|
||||
['priceList', () => import('./basics/price/pc/index.vue')], // 定价捆绑
|
||||
['discountList', () => import('./basics/discount/pc/index.vue')], // 限时折扣
|
||||
['newProduct', () => import('./basics/newProduct/app/index.vue')], // 每日上新
|
||||
['shop', () => import('./basics/shop.vue')], // 每日好店
|
||||
]),
|
||||
]
|
||||
export default componentMap
|
19
components/canvasShow/config/api.js
Normal file
19
components/canvasShow/config/api.js
Normal file
@ -0,0 +1,19 @@
|
||||
// 导入api接口模块
|
||||
import { VUE_APP_API_URL } from '@/config'
|
||||
// 获取当前环境变量 true => 生产环境 false => 开发环境
|
||||
// const BASEURL = process.env.VUE_APP_DOMAIN_PREFIX
|
||||
const BASEURL = VUE_APP_API_URL
|
||||
// const BASEURL = (process.env.NODE_ENV === 'production') ? 'http://127.0.0.1:9007' : 'http://127.0.0.1:9007'
|
||||
|
||||
|
||||
export const api = {
|
||||
// 画布模块
|
||||
getCanvas: BASEURL + '/shop/canvas/canvas-json', // 读取画布
|
||||
getProducts: BASEURL + '/product/canvas/page', // 选择商品查询
|
||||
getCoupons: BASEURL + '/product/coupon/canvas-list', // 优惠券查询
|
||||
takeCoupon: BASEURL + '/product/coupon/relation/receive/', // 领取优惠券
|
||||
getActivityProduct: `${BASEURL}/product/campaign/product-page`, // 获取活动商品
|
||||
getActivity: `${BASEURL}/product/campaign/get`, // 获取单个活动
|
||||
|
||||
}
|
||||
export default api
|
24
components/canvasShow/config/config.js
Normal file
24
components/canvasShow/config/config.js
Normal file
@ -0,0 +1,24 @@
|
||||
// 画布配置
|
||||
// import Cookies from 'js-cookie'
|
||||
|
||||
const config = {
|
||||
terminal: 4, // 画布设备 1 小程序,2 H5,3 App 4 电脑
|
||||
typeId: 0, // 页面类型 0 C端 1 平台画布,2 自定义页面,3 商家店铺装修
|
||||
getToken: function(){
|
||||
return uni.getStorageSync('storage_key').token
|
||||
}
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
config.terminal = 2
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS || APP-NVUE
|
||||
config.terminal = 3
|
||||
// #endif
|
||||
|
||||
// #ifdef MP
|
||||
config.terminal = 1
|
||||
// #endif
|
||||
|
||||
export default config
|
196
components/canvasShow/config/mixin/funMixin.js
Normal file
196
components/canvasShow/config/mixin/funMixin.js
Normal file
@ -0,0 +1,196 @@
|
||||
import sendReqMixin from './sendReqMixin'
|
||||
import { useRouter } from "@/hooks/useRouter";
|
||||
|
||||
export default function () {
|
||||
const {sendReq} = sendReqMixin()
|
||||
const {push} = useRouter()
|
||||
|
||||
// 请求数据前 请求完再显示所有组件
|
||||
function beforeGetData() {
|
||||
if (typeof uni !== 'undefined') {
|
||||
uni.getStorage({
|
||||
key: 'sendNum',
|
||||
success: function (res) {
|
||||
const sendNum = res.data
|
||||
uni.setStorage({key: 'sendNum', data: parseInt(sendNum) + 1})
|
||||
},
|
||||
})
|
||||
} else {
|
||||
const sendNum = localStorage.getItem('sendNum')
|
||||
localStorage.setItem('sendNum', parseInt(sendNum) + 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 请求数据后
|
||||
function afterGetData() {
|
||||
if (typeof uni !== 'undefined') {
|
||||
uni.getStorage({
|
||||
key: 'sendNum',
|
||||
success: function (res) {
|
||||
const sendNum = res.data
|
||||
uni.setStorage({key: 'sendNum', data: parseInt(sendNum) - 1})
|
||||
},
|
||||
})
|
||||
} else {
|
||||
const sendNum = localStorage.getItem('sendNum')
|
||||
localStorage.setItem('sendNum', parseInt(sendNum) - 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断url
|
||||
function jumpLink(linkObj) {
|
||||
console.log(linkObj, 'linkObj')
|
||||
var link = ''
|
||||
if (linkObj?.typeText) {
|
||||
switch (linkObj.typeText) {
|
||||
case '类别':
|
||||
jumpCategory(linkObj.data.id)
|
||||
break
|
||||
case '店辅':
|
||||
jumpStore(linkObj.data)
|
||||
break
|
||||
case '商品':
|
||||
jumpProductDetail(linkObj.data)
|
||||
break
|
||||
case '自定义':
|
||||
// router.push("/category");
|
||||
case '公告':
|
||||
jumpNoticeDetail(linkObj.data)
|
||||
break
|
||||
case '产品':
|
||||
jumpProList()
|
||||
break
|
||||
case '秒杀':
|
||||
jumpSeckills()
|
||||
break
|
||||
case '拼团':
|
||||
jumpGroupWorks()
|
||||
break
|
||||
case '折扣':
|
||||
jumpDiscount()
|
||||
break
|
||||
}
|
||||
} else if (linkObj?.selsectValue === '/index') {
|
||||
uni.navigateTo({
|
||||
url: `/root/index/index`
|
||||
})
|
||||
}
|
||||
return link
|
||||
}
|
||||
|
||||
// 跳转到搜索
|
||||
function toSearch(key) {
|
||||
push({
|
||||
url: '/pages/search/search'
|
||||
}, {
|
||||
data: {key}
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到类别主页
|
||||
function jumpCategory(id) {
|
||||
push({
|
||||
url: '/pages/goodsList/goodsList'
|
||||
}, {
|
||||
data: {sid: id}
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到产品列表
|
||||
function jumpProList(item) {
|
||||
push({
|
||||
url: '/pages/goodsList/goodsList'
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到店铺主页
|
||||
function jumpStore(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages_category_page1/store/index?storeId=${ item.shopId }`
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到商品详情
|
||||
function jumpProductDetail(item) {
|
||||
push({url: '/pages/goodsDetail/goodsDetail'}, {data: {id:item.id,skuId:item.skuId}})
|
||||
}
|
||||
|
||||
// 跳转到秒杀专区
|
||||
function jumpSeckills() {
|
||||
push({url: '/pages/seckilling/seckilling'})
|
||||
}
|
||||
|
||||
// 跳转到拼团专区
|
||||
function jumpGroupWorks() {
|
||||
push({url: '/pages/groupBuy/groupBuy'})
|
||||
}
|
||||
|
||||
// 跳转到折扣专区
|
||||
function jumpDiscount() {
|
||||
push({url: '/pages/discount/discount'})
|
||||
}
|
||||
|
||||
// 跳转到会员专区
|
||||
function jumpVip() {
|
||||
uni.navigateTo({
|
||||
url: '/pages_category_page1/memberCenter/activityList',
|
||||
success: res => {
|
||||
}, fail: () => {
|
||||
}, complete: () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转组合支付
|
||||
function jumpCombination(item) {
|
||||
if (item.priceId) {
|
||||
uni.navigateTo({
|
||||
url: '/pages_category_page1/goodsModule/combination?priceId=' + item.priceId
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '暂无活动',
|
||||
icon: "none"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转到公告详情
|
||||
function jumpNoticeDetail(item) {
|
||||
uni.navigateTo({
|
||||
url: '/pages_category_page2/userModule/messageDetail?noticeId=' + item.noticeId
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到直播列表
|
||||
function jumpLive() {
|
||||
uni.navigateTo({
|
||||
url: '/pages_category_page2/livePage/index'
|
||||
})
|
||||
}
|
||||
|
||||
// 加入购物车
|
||||
function addCart(id) {
|
||||
console.log(id)
|
||||
}
|
||||
|
||||
return {
|
||||
beforeGetData,
|
||||
afterGetData,
|
||||
toSearch,
|
||||
sendReq,
|
||||
jumpLink,
|
||||
jumpCategory,
|
||||
jumpStore,
|
||||
jumpProductDetail,
|
||||
jumpSeckills,
|
||||
jumpGroupWorks,
|
||||
jumpDiscount,
|
||||
jumpVip,
|
||||
jumpNoticeDetail,
|
||||
addCart,
|
||||
jumpProList,
|
||||
jumpLive,
|
||||
jumpCombination
|
||||
}
|
||||
}
|
4
components/canvasShow/config/mixin/index.js
Normal file
4
components/canvasShow/config/mixin/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
import fun from './funMixin.js'
|
||||
import sendReq from './sendReqMixin.js'
|
||||
export const funMixin = fun
|
||||
export const sendReqMixin = sendReq
|
25
components/canvasShow/config/mixin/sendReqMixin.js
Normal file
25
components/canvasShow/config/mixin/sendReqMixin.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { ref } from 'vue';
|
||||
import request from './server'
|
||||
|
||||
export default function () {
|
||||
const loading = ref(false)
|
||||
/*
|
||||
* 发送请求
|
||||
*/
|
||||
|
||||
function sendReq (params, callback) {
|
||||
request(params.url, params.data || {},params.method || 'POST',{
|
||||
'Content-type': params.contentType || 'application/json;charset=utf-8'
|
||||
}).then((res) => {
|
||||
if (res && res.data) {
|
||||
callback && callback(res.data)
|
||||
}
|
||||
}, (error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
return {
|
||||
loading,
|
||||
sendReq
|
||||
}
|
||||
}
|
234
components/canvasShow/config/mixin/server.js
Normal file
234
components/canvasShow/config/mixin/server.js
Normal file
@ -0,0 +1,234 @@
|
||||
// 引入axios
|
||||
// import router from './../../router'
|
||||
// import * as Vue from 'vue'
|
||||
// import promise from 'es6-promise'
|
||||
import axios from 'axios'
|
||||
import canvasConfig from '../config'
|
||||
import cookie from '@/utils/cookie'
|
||||
// import Cookies from 'js-cookie'
|
||||
// import localStorage from '../storage/localStorage'
|
||||
// promise.polyfill()
|
||||
|
||||
/*
|
||||
const service = axios.create({
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
withCredentials: true,
|
||||
timeout: 20000 // 请求超时 20s
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(config => {
|
||||
// 是否为当前的请求加上请求头 token
|
||||
const token = canvasConfig.getToken()
|
||||
if (token) {
|
||||
if(canvasConfig.typeId === 1){
|
||||
config.headers['Authorization-admin'] = token
|
||||
} else if(canvasConfig.typeId === 3){
|
||||
config.headers['Authorization-business'] = token
|
||||
} else {
|
||||
config.headers['Authorization'] = token
|
||||
}
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
console.log(response)
|
||||
if (response.data.code && response.data.code !=='200' && response.data.message) {
|
||||
// Vue.prototype.$message.error(response.data.message)
|
||||
uni.showToast({
|
||||
title:response.data.message,
|
||||
icon:"none"
|
||||
})
|
||||
}
|
||||
return response
|
||||
},
|
||||
err => {
|
||||
console.log(err)
|
||||
// 失败响应
|
||||
if (err && err.response) {
|
||||
switch (err.response.status) {
|
||||
case 400:
|
||||
err.message = '请求无效,请检查参数是否正确!'
|
||||
break
|
||||
|
||||
case 401:
|
||||
err.message = '未经授权,访问被拒!'
|
||||
break
|
||||
|
||||
case 403:
|
||||
err.message = '拒绝访问!'
|
||||
break
|
||||
|
||||
case 404:
|
||||
err.message = `地址不存在!`
|
||||
break
|
||||
|
||||
case 408:
|
||||
err.message = '请求超时!'
|
||||
break
|
||||
|
||||
case 500:
|
||||
err.message = '系统错误!'
|
||||
break
|
||||
|
||||
case 501:
|
||||
err.message = '该方法未实现!'
|
||||
break
|
||||
|
||||
case 502:
|
||||
err.message = '网关出错!'
|
||||
break
|
||||
|
||||
case 503:
|
||||
err.message = '服务不可用!'
|
||||
break
|
||||
|
||||
case 504:
|
||||
err.message = '网关请求超时'
|
||||
break
|
||||
|
||||
case 505:
|
||||
err.message = 'HTTP版本不受支持'
|
||||
break
|
||||
|
||||
default:
|
||||
}
|
||||
if (err.response.data.error) {
|
||||
err.message = err.response.data.error
|
||||
}
|
||||
// Vue.prototype.$message.closeAll()
|
||||
// Vue.prototype.$message.error(err.message)
|
||||
uni.showToast({
|
||||
title:err.message,
|
||||
icon:"none"
|
||||
})
|
||||
// router.push({name: 'error', params: {message: err.message, status: err.response.status}})
|
||||
}
|
||||
}
|
||||
)
|
||||
*/
|
||||
|
||||
const request = (url,data,method='GET',header={})=>new Promise((resolve, reject)=>{
|
||||
// 是否为当前的请求加上请求头 token
|
||||
const token = cookie.get('accessToken')
|
||||
const headers = {...header}
|
||||
if (token.accessToken) {
|
||||
headers['Authorization'] = 'Bearer ' + token.accessToken
|
||||
}
|
||||
uni.request({
|
||||
url: url,
|
||||
data: data,
|
||||
method: method,
|
||||
header: headers,
|
||||
success: response => {
|
||||
if (response.data.code && response.data.code !=='200' && response.data.message) {
|
||||
uni.showToast({
|
||||
title:response.data.message,
|
||||
icon:"none"
|
||||
})
|
||||
}else{
|
||||
resolve(response)
|
||||
}
|
||||
},
|
||||
fail: err => {
|
||||
// 失败响应
|
||||
if (err && err.response) {
|
||||
switch (err.response.status) {
|
||||
case 400:
|
||||
err.message = '请求无效,请检查参数是否正确!'
|
||||
break
|
||||
|
||||
case 401:
|
||||
err.message = '未经授权,访问被拒!'
|
||||
break
|
||||
|
||||
case 403:
|
||||
err.message = '拒绝访问!'
|
||||
break
|
||||
|
||||
case 404:
|
||||
err.message = `地址不存在!`
|
||||
break
|
||||
|
||||
case 408:
|
||||
err.message = '请求超时!'
|
||||
break
|
||||
|
||||
case 500:
|
||||
err.message = '系统错误!'
|
||||
break
|
||||
|
||||
case 501:
|
||||
err.message = '该方法未实现!'
|
||||
break
|
||||
|
||||
case 502:
|
||||
err.message = '网关出错!'
|
||||
break
|
||||
|
||||
case 503:
|
||||
err.message = '服务不可用!'
|
||||
break
|
||||
|
||||
case 504:
|
||||
err.message = '网关请求超时'
|
||||
break
|
||||
|
||||
case 505:
|
||||
err.message = 'HTTP版本不受支持'
|
||||
break
|
||||
|
||||
default:
|
||||
}
|
||||
if (err.response.data.error) {
|
||||
err.message = err.response.data.error
|
||||
}
|
||||
// Vue.prototype.$message.closeAll()
|
||||
// Vue.prototype.$message.error(err.message)
|
||||
uni.showToast({
|
||||
title:err.message,
|
||||
icon:"none"
|
||||
})
|
||||
reject(err)
|
||||
// router.push({name: 'error', params: {message: err.message, status: err.response.status}})
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
//真机获取
|
||||
// service.defaults.adapter = function (config) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// console.log(config)
|
||||
// var settle = require('axios/lib/core/settle');
|
||||
// var buildURL = require('axios/lib/helpers/buildURL');
|
||||
// uni.request({
|
||||
// method: config.method.toUpperCase(),
|
||||
// url: buildURL(config.url, config.params, config.paramsSerializer),
|
||||
// header: config.headers,
|
||||
// data: config.data,
|
||||
// dataType: config.dataType,
|
||||
// responseType: config.responseType,
|
||||
// sslVerify: config.sslVerify,
|
||||
// complete:function complete(response){
|
||||
// response = {
|
||||
// data: response.data,
|
||||
// status: response.statusCode,
|
||||
// errMsg: response.errMsg,
|
||||
// header: response.header,
|
||||
// config: config
|
||||
// };
|
||||
//
|
||||
// settle(resolve, reject, response);
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
export default request
|
Reference in New Issue
Block a user