Browse Source

初始化项目

master
panxiaohe 2 years ago
commit
bc7216f5e3
  1. 25
      .gitignore
  2. 768
      App.vue
  3. 2
      Dockerfile
  4. 269
      component/share.vue
  5. 388
      components/AliHbPay/index.vue
  6. 320
      components/CashierList/index.vue
  7. 72
      components/Empty/index.vue
  8. 24
      components/GlobalLoading/index.js
  9. 89
      components/GlobalLoading/index.vue
  10. 250
      components/Loading/index.vue
  11. 54
      components/NoMore/index.vue
  12. 200
      components/Skeleton/index.vue
  13. 633
      components/activities/combinedSales.vue
  14. 430
      components/adWindow.vue
  15. 84
      components/basics/categoryList.vue
  16. 280
      components/basics/categoryShow.vue
  17. 24
      components/canvasShow/basics/assistDiv.vue
  18. 107
      components/canvasShow/basics/banner.vue
  19. 131
      components/canvasShow/basics/brandList.vue
  20. 109
      components/canvasShow/basics/categoryList.vue
  21. 113
      components/canvasShow/basics/coupon/app/index.vue
  22. 109
      components/canvasShow/basics/coupon/mixin.js
  23. 375
      components/canvasShow/basics/coupon/pc/index.vue
  24. 238
      components/canvasShow/basics/custom.vue
  25. 300
      components/canvasShow/basics/discount/app/index.vue
  26. 110
      components/canvasShow/basics/discount/mixin.js
  27. 247
      components/canvasShow/basics/discount/pc/index.vue
  28. 213
      components/canvasShow/basics/group/app/index.vue
  29. 86
      components/canvasShow/basics/group/mixin.js
  30. 250
      components/canvasShow/basics/group/pc/index.vue
  31. 118
      components/canvasShow/basics/header/app/index.vue
  32. 45
      components/canvasShow/basics/header/mixin.js
  33. 119
      components/canvasShow/basics/imageText.vue
  34. 136
      components/canvasShow/basics/imageTextList.vue
  35. 101
      components/canvasShow/basics/imageTextNav.vue
  36. 71
      components/canvasShow/basics/live/app/index.vue
  37. 461
      components/canvasShow/basics/live/app/item.vue
  38. 60
      components/canvasShow/basics/live/mixin.js
  39. 196
      components/canvasShow/basics/newProduct/app/index.vue
  40. 89
      components/canvasShow/basics/newProduct/mixin.js
  41. 96
      components/canvasShow/basics/notice.vue
  42. 218
      components/canvasShow/basics/price/app/index.vue
  43. 73
      components/canvasShow/basics/price/mixin.js
  44. 253
      components/canvasShow/basics/price/pc/index.vue
  45. 564
      components/canvasShow/basics/product/app/index.vue
  46. 96
      components/canvasShow/basics/product/mixin.js
  47. 226
      components/canvasShow/basics/product/pc/index.vue
  48. 157
      components/canvasShow/basics/shop.vue
  49. 168
      components/canvasShow/basics/spike/app/index.vue
  50. 137
      components/canvasShow/basics/spike/mixin.js
  51. 211
      components/canvasShow/basics/spike/pc/index.vue
  52. 79
      components/canvasShow/basics/text.vue
  53. 120
      components/canvasShow/basics/video.vue
  54. 319
      components/canvasShow/basics/vip/app/index.vue
  55. 60
      components/canvasShow/basics/vip/mixin.js
  56. 241
      components/canvasShow/basics/vip/pc/index.vue
  57. 226
      components/canvasShow/canvasShowPage.vue
  58. 32
      components/canvasShow/config/api.js
  59. 12
      components/canvasShow/config/config.js
  60. 204
      components/canvasShow/config/mixin/funMixin.js
  61. 9
      components/canvasShow/config/mixin/index.js
  62. 37
      components/canvasShow/config/mixin/sendReqMixin.js
  63. 135
      components/canvasShow/config/mixin/server.js
  64. BIN
      components/canvasShow/static/images/btn-next.png
  65. BIN
      components/canvasShow/static/images/btn-next2.png
  66. BIN
      components/canvasShow/static/images/btn-prev.png
  67. BIN
      components/canvasShow/static/images/btn-prev2.png
  68. BIN
      components/canvasShow/static/images/coupon/bg-coupon.png
  69. BIN
      components/canvasShow/static/images/coupon/bg-coupon2.png
  70. BIN
      components/canvasShow/static/images/coupon/border_L1.png
  71. 0
      components/canvasShow/static/images/coupon/border_L2.png
  72. 0
      components/canvasShow/static/images/coupon/border_L3.png
  73. 0
      components/canvasShow/static/images/coupon/border_L4.png
  74. 0
      components/canvasShow/static/images/coupon/border_R1.png
  75. 0
      components/canvasShow/static/images/coupon/border_R2.png
  76. 0
      components/canvasShow/static/images/coupon/border_R3.png
  77. 0
      components/canvasShow/static/images/coupon/border_R4.png
  78. BIN
      components/canvasShow/static/images/coupon/flag-coupon-r.png
  79. BIN
      components/canvasShow/static/images/coupon/flag-coupon.png
  80. BIN
      components/canvasShow/static/images/coupon/flag-coupon2-r.png
  81. BIN
      components/canvasShow/static/images/coupon/flag-coupon2.png
  82. BIN
      components/canvasShow/static/images/discount/bg-discount-top-text.png
  83. BIN
      components/canvasShow/static/images/discount/bg-discount-top.png
  84. BIN
      components/canvasShow/static/images/discount/flag-discount.png
  85. BIN
      components/canvasShow/static/images/discount/flag-discount2.png
  86. BIN
      components/canvasShow/static/images/discount/img-title.png
  87. BIN
      components/canvasShow/static/images/discountListIcon.png
  88. BIN
      components/canvasShow/static/images/group/flag-group.png
  89. BIN
      components/canvasShow/static/images/group/img-title.png
  90. BIN
      components/canvasShow/static/images/groupBuyIcon.png
  91. BIN
      components/canvasShow/static/images/icon-title.png
  92. BIN
      components/canvasShow/static/images/live/huabei.png
  93. BIN
      components/canvasShow/static/images/live/icon-live-num.png
  94. BIN
      components/canvasShow/static/images/live/img-title.png
  95. BIN
      components/canvasShow/static/images/memberCenterIcon.png
  96. BIN
      components/canvasShow/static/images/newProduct/bg-product-card.png
  97. BIN
      components/canvasShow/static/images/newProduct/flag-new.png
  98. BIN
      components/canvasShow/static/images/notice/ico_notice.png
  99. BIN
      components/canvasShow/static/images/notice/ico_notice2.png
  100. BIN
      components/canvasShow/static/images/price/bg-discount.png

25
.gitignore

@ -0,0 +1,25 @@
.DS_Storep
.DS_Store
# Editor directories and files
.idea
.vscode
.hbuilderx
*.suo
*.ntvs*
*.njsproj
*.sln
*.hbuilderx
/unpackage/dist/dev
/unpackage/dist/static
/unpackage/dist/build/mp-alipay/
/unpackage/dist/build/mp-weixin/
/unpackage/dist/build/app-plus/
/unpackage/dist/build/.automator
/unpackage/cache/
/unpackage/cache/apk
/unpackage/release
/unpackage/res
/unpackage/resources
/node_modules
package-lock.json

768
App.vue

@ -0,0 +1,768 @@
<script>
// // #ifdef MP-WEIXIN
// const miniShopPlugin = requirePlugin('mini-shop-plugin');
// // #endif
import NET from "@/utils/request";
import API from "@/config/api";
export default {
onLaunch: function (options) {
if (options && options.path === 'pages_category_page1/goodsModule/goodsDetails' && options.query) {
this.globalData.productShareItem = options.query
}
if (options && options.path === 'pages_category_page1/store/index' && options.query) {
this.globalData.shopShareItem = options.query
}
if (options && options.path === 'pages_category_page1/distributionModule/recruit' && options.query) {
this.globalData.distributeRecruitItem = options.query
}
if (options && options.path === 'pages_category_page1/goodsModule/inviteSpell' && options.query) {
this.globalData.inviteSpellShareItem = options.query
}
// iPhone
const self = this
uni.getSystemInfo({
success: function (res) {
console.log(res, '检查机型')
// model
// const iphoneModels = [
// 'iPhone X',
// 'iPhone XR',
// 'iPhone XS Max',
// 'iPhone 11',
// 'iPhone 11 Pro',
// 'iPhone 11 Pro Max',
// 'iPhone 12/13 (Pro)',
// 'iPhone 12/13 mini',
// 'iPhone 12/13 Pro Max'
// ]
if (res.safeArea.top > 20 && res.model.indexOf('iPhone') !== -1) {
self.globalData.isIphone = true
}
}
})
//
if(uni.getStorageSync('storage_key')){
NET.request(API.ShoppingCart, {}, 'GET').then(resCart => {
let cartNum = 0
resCart.data.forEach(shopItem=>{
shopItem.skus.forEach(goodsItem=>{
cartNum += goodsItem.number
})
})
uni.setStorageSync('allCartNum', cartNum)
if (cartNum > 0) {
uni.setTabBarBadge({
index: 2,
text: cartNum.toString()
})
}
})
}
}
,
globalData: {
isIphone: false,
}
,
}
;
</script>
<style lang="scss">
@keyframes loading {
0%{
background: #e7e7e7;
}
50%{
background: #f8f8f8;
}
100%{
background: #e7e7e7;
}
}
//
.ske-loading{
.child-loading{
animation: loading 2s linear 0s infinite alternate;
}
}
/*每个页面公共css */
@import "uview-ui/index.scss";
uni-rich-text img {
max-width: 100% !important;
}
//
.pic-img{
width: 100%;
height: 100%;
}
.default-img {
background: url(./static/images/default.png) no-repeat center;
background-size: 100% 100%;
}
.line1 {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.wid {
width: 100%;
}
.fs4 {
font-size: 4upx;
}
.fs18 {
font-size: 18upx;
}
.fs20 {
font-size: 20upx;
}
.fs22 {
font-size: 22upx;
}
.fs24 {
font-size: 24upx;
}
.fs26 {
font-size: 26upx;
}
.fs28 {
font-size: 28upx;
}
.fs30 {
font-size: 30upx;
}
.fs32 {
font-size: 32upx;
}
.fs34 {
font-size: 34upx;
}
.fs36 {
font-size: 36upx;
}
.fs38 {
font-size: 38upx;
}
.fs40 {
font-size: 40upx;
}
.fs42 {
font-size: 42upx;
}
.fs44 {
font-size: 44upx;
}
.fs46 {
font-size: 46upx;
}
.fs48 {
font-size: 46upx;
}
.fs50 {
font-size: 50upx;
}
.fs60 {
font-size: 60upx;
}
.fs-bold {
font-weight: bold;
}
.fs-weight-300 {
font-weight: 300;
}
.fs-weight-200 {
font-weight: 200;
}
.fs-weight-400 {
font-weight: 400;
}
.flex-display {
display: flex;
}
.flex-center {
display: flex;
justify-content: center;
}
.flex-items {
display: flex;
align-items: center;
}
.flex-items-plus {
display: flex;
justify-content: center;
align-items: center;
}
.flex-start {
display: flex;
justify-content: flex-start;
}
.flex-end {
display: flex;
justify-content: flex-end;
}
.flex-end-plus {
display: flex;
justify-content: flex-end;
align-items: center;
}
.flex-column {
flex-direction: column
}
.flex-column-plus {
display: flex;
flex-direction: column
}
.flex-row {
flex-direction: row
}
.flex-row-plus {
display: flex;
flex-direction: row
}
.flex-sp-around {
justify-content: space-around;
}
.flex-sp-between {
justify-content: space-between;
}
.text-align {
text-align: center;
}
.flex-wrap-1 {
display: flex;
flex-wrap: wrap
}
.flex-nowrap-1 {
display: flex;
flex-wrap: nowrap
}
.align-end {
display: flex;
align-items: flex-end;
}
.align-sp-between {
align-content: space-between;
}
.mar-top-5 {
margin-top: 5upx;
}
.mar-top-10 {
margin-top: 10upx;
}
.mar-top-20 {
margin-top: 20upx;
}
.mar-top-30 {
margin-top: 30upx;
}
.mar-top-32 {
margin-top: 32upx;
}
.mar-top-36 {
margin-top: 36upx;
}
.mar-top-40 {
margin-top: 40upx;
}
.mar-top-50 {
margin-top: 50upx;
}
.mar-top-60 {
margin-top: 60upx;
}
.mar-top-70 {
margin-top: 70upx;
}
.mar-top-100 {
margin-top: 100upx;
}
.mar-top-percent40 {
margin-top: 40%;
}
.mar-top-half {
margin-top: 50%;
}
.mar-left-6 {
margin-left: 6upx;
}
.mar-left-5 {
margin-left: 5upx;
}
.mar-left-10 {
margin-left: 10upx;
}
.mar-left-20 {
margin-left: 20upx;
}
.mar-left-30 {
margin-left: 30upx;
}
.mar-left-35 {
margin-left: 35upx;
}
.mar-left-40 {
margin-left: 40upx;
}
.mar-left-50 {
margin-left: 50upx;
}
.mar-left-60 {
margin-left: 60upx;
}
.mar-left-70 {
margin-left: 70upx;
}
.mar-right-10 {
margin-right: 10upx;
}
.mar-right-20 {
margin-right: 20upx;
}
.mar-right-25 {
margin-right: 25upx;
}
.mar-right-30 {
margin-right: 30upx;
}
.mar-right-35 {
margin-right: 35upx;
}
.mar-right-40 {
margin-right: 40upx;
}
.mar-right-50 {
margin-right: 50upx;
}
.pad-left-10 {
padding-left: 10upx;
}
.pad-left-20 {
padding-left: 20upx;
}
.pad-left-40 {
padding-left: 40upx;
}
.pad-right-20 {
padding-right: 20upx;
}
.pad-top-20 {
padding-top: 20upx;
}
.pad-top-40 {
padding-top: 40upx;
}
.pad-bot-20 {
padding-bottom: 20upx;
}
.pad-topbot-20 {
padding: 20upx 0upx;
}
.pad-topbot-5 {
padding: 0upx 5upx;
}
.pad-topbot-10 {
padding: 0upx 10upx;
}
.pad-topbot-50 {
padding: 50upx 0upx;
}
.pad-bot-20 {
padding-bottom: 20upx;
}
.pad-bot-30 {
padding-bottom: 30upx;
}
.pad-bot-40 {
padding-bottom: 40upx;
}
.pad-bot-100 {
padding-bottom: 100upx;
}
.pad-bot-140 {
padding-bottom: 140upx;
}
.bor-rad-30 {
border-radius: 30upx;
}
.bor-rad-45 {
border-radius: 45upx;
}
.bor-rad-half {
border-radius: 50%;
}
.backColor {
background-color: #009688;
}
.backColorFFF {
background-color: #FFFFFF;
}
.pos-abs {
position: absolute;
}
.bor-bot-line {
border-bottom: #C8C7CC 1upx solid;
}
.bor-line-F7F7F7 {
border-bottom: #F7F7F7 1upx solid;
}
.bor-line-E5E5E5 {
border-bottom: #E5E5E5 1upx solid;
}
.borRig-line-E5E5E5 {
border-right: #DDDDDD 2upx solid;
}
.borRig-line-20 {
border-bottom: #F7F7F7 20upx solid;
}
.font-color-red {
color: red;
}
.font-color-FFF {
color: #FFFFFF;
}
.font-color-8A734A {
color: #8A734A;
}
.font-color-71521B {
color: #71521B;
}
.font-color-222 {
color: #222222;
}
.font-color-333 {
color: #333333;
}
.font-color-666 {
color: #666666;
}
.font-color-999 {
color: #999999;
}
.font-color-656 {
color: #656565;
}
.font-color-DDD {
color: #DDDDDD;
}
.font-color-CCC {
color: #CCCCCC;
}
.font-color-FFEBC4 {
color: #FFEBC4;
}
.font-color-1CC363 {
color: #1CC363;
}
.font-color-47A7EE {
color: #47A7EE;
}
.font-color-C5AA7B {
color: #C5AA7B;
}
.font-color-FF7700 {
color: #FF7700;
}
.font-color-FF7911 {
color: #FF7911;
}
.font-color-80 {
color: #808080;
}
.font-color-DD {
color: #DD524D;
}
.font-color-C83732 {
color: #C83732;
}
.font-color-3F {
color: #3F536E;
}
.font-color-009 {
color: #009688;
}
.font-weight-500 {
font-weight: 500;
}
.font-weight-bold {
font-weight: bold;
}
.overflow {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.overflowNoDot {
display: block;
overflow: hidden;
}
.discountsPriceLine {
text-decoration: line-through;
}
.border-bottom-Line {
border-bottom: 1upx solid #EDEDED;
}
.decoration {
text-decoration: line-through;
}
.anonymous {
margin-top: 25upx;
.uni-checkbox-input {
border-color: #C5AA7B !important;
width: 30upx;
height: 30upx;
}
.uni-checkbox-input-checked:before {
font-size: 30upx !important;
}
.uni-checkbox-input-checked {
background: #C5AA7B;
}
}
.footprint {
.itemList {
.uni-checkbox-input {
border-color: #C5AA7B !important;
width: 36upx;
height: 36upx;
border-radius: 50%;
margin-right: 20upx;
}
.uni-checkbox-input-checked:before {
font-size: 36upx !important;
}
.uni-checkbox-input-checked {
background: #C5AA7B;
}
}
}
.itemInfo {
uni-slider {
margin: 0;
.uni-slider-thumb {
display: none;
}
.uni-slider-handle-wrapper {
height: 18upx;
border-radius: 0;
border: 1upx solid #FF736C;
}
.uni-slider-track {
border-radius: 0;
}
.uni-slider-tap-area {
flex: 0 0 70%;
padding: 0;
}
}
}
.uni-modal {
padding: 20rpx;
box-sizing: border-box;
}
uni-modal .uni-modal__ft:after {
border-top: none;
}
uni-modal .uni-modal__btn {
color: #333333;
border: 2rpx solid #333333;
font-weight: 400;
margin: 0 10rpx;
font-size: 28rpx;
}
.uni-tabbar .uni-tabbar__reddot {
background: #C5AA7B;
color: #FFFFFF;
}
uni-checkbox:not([disabled]) .uni-checkbox-input:hover {
border-color: #C5AA7B;
}
.u-arrow {
display: inline-block;
width: 20rpx;
height: 20rpx;
border-top: 1rpx solid #999;
border-right: 1rpx solid #999;
}
.u-arrow-up {
transform: rotate(-45deg);
}
.u-arrow-down {
transform: rotate(135deg);
}
.u-arrow-left {
transform: rotate(-135deg);
}
.u-arrow-right {
transform: rotate(45deg);
}
.uni-picker-container .uni-picker-action.uni-picker-action-confirm {
color: #C5AA7B;
}
.u-drawer-content {
//border-radius: 0 !important;
}
</style>
<style>
.uni-modal__btn_primary {
background: #333333;
color: #FFEBC4 !important;
}
</style>

2
Dockerfile

@ -0,0 +1,2 @@
FROM registry.cn-shenzhen.aliyuncs.com/sumply-shop/nginx
COPY unpackage/dist/build/h5/ /home/ui-h5/

269
component/share.vue

@ -0,0 +1,269 @@
<template>
<div>
<u-popup v-model="shareShow" :round="10" mode="bottom" @close="cancel(1)">
<view class="share">
<!-- <u-mask :show="true" class="flex-items-plus flex-row"> -->
<text class="h3">邀请好友</text>
<view class="share-list">
<view class="ul">
<!-- #ifdef APP-PLUS -->
<view class="li" @click="share('weixin')">
<image class="icon" src="../static/images/share/weixin2x.png"></image>
<label class="label">微信</label>
</view>
<view class="li" @click="share('weixinpyq')">
<image class="icon" src="../static/images/share/pyq.png"></image>
<label class="label">朋友圈</label>
</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view class="li">
<button open-type="share" @share='onShareAppMessage' :data-obj="wxShareData" class="share-button">
<image class="icon" src="../static/images/share/forward.png"></image>
<label class="label">好友</label>
</button>
</view>
<view class="li" @click="share('weixinpyq')">
<image class="icon" src="../static/images/share/pyq.png"></image>
<label class="label">朋友圈</label>
</view>
<!-- #endif -->
<view class="li" @click="share('lianjie')">
<image class="icon" src="../static/images/share/lianjie.png"></image>
<label class="label">链接</label>
</view>
</view>
</view>
<view class="btn-close" @click="cancel(1)">取消</view>
</view>
</u-popup>
<u-popup v-model="wapShow" :round="10" mode="bottom" :border-radius="10" @close="cancel(2)">
<view class="share-h5">
<view class="text">
点击浏览器下方
<view class="icon">
<u-icon name="list" color="#fff" size="28"></u-icon>
</view>
即可进行分享
</view>
</view>
</u-popup>
</div>
</template>
<script>
import ClipboardJS from "clipboard"
import UImage from "../uview-ui/components/u-image/u-image";
const API = require('../config/api')
export default {
components: {UImage},
props: {
img: {
type: String,
default: ""
},
url: {
type: String,
dafault: ''
},
title: {
type: String,
dafault: ''
},
urlParms: {
type: String,
default: ''
},
},
onShareAppMessage(e) {
if(e.from=='button'){
// button
}
if(e.from=='menu'){
//
}
// data item
let params = e.target.dataset.obj// data item
return {
path: `/pages_category_page1/goodsModule/inviteSpell?${params.url}`
}
},
name: "share",
data() {
return {
shareShow: false,
wapShow: false,
wxShareData: {
url: ''
}
// longUrl: ''
};
},
mounted() {
// this.longUrl = API.shareLink + '/#' + this.url
// console.log(this.longUrl, this.url
this.wxShareData = this.url
},
computed:{
longUrl(){
return API.shareLink + '/#' + this.url
}
},
methods: {
cancel(key) {
if (key === 1) {
this.shareShow = false
this.$emit('shareCancel')
} else if (key === 2) {
this.wapShow = false
}
},
wxShare(type) {
// #ifdef APP-PLUS
uni.share({
provider: "weixin",
type: 0,
title: this.title,
scene: type,//WXSceneSession WXSceneTimeline
imageUrl: this.img,
href: this.longUrl,
success: () => {
},
fail: (err) => {
console.log("err",err)
}
})
// #endif
// #ifdef MP-WEIXIN
uni.showToast({
title:"请点击右上角打开菜单进行朋友圈分享",
icon:"none"
})
// #endif
},
share(key) {
switch (key) {
case 'weixin':
this.wxShare("WXSceneSession")
break
case 'weixinpyq':
this.wxShare("WXSceneTimeline")
break
case 'qq':
break
case 'weibo':
break
case 'lianjie':
uni.setClipboardData({
data: this.title + this.longUrl,
success: () => {
uni.showToast({
title: '复制成功'
})
}
})
break
}
},
//
overShare: function () {
//
//
wx.onAppRoute(function (res) {
//
let pages = getCurrentPages(),
//
view = pages[pages.length - 1],
data;
if (view) {
data = view.data;
console.log('是否重写分享方法', data.isOverShare);
if (!data.isOverShare) {
data.isOverShare = true;
view.onShareAppMessage = function () {
//
return {
title: '标题',
path: '/pages/nearby/index'
};
}
}
}
})
}
}
}
</script>
<style lang="scss">
.share{
background-color: #F8F8F8;
text-align: center;
.h3{
font-size: 30rpx;
color: #333333;
line-height: 42rpx;
padding: 30rpx 0;
border-bottom: 2px solid #F0F0F0;
display: block;
}
.share-list{
padding: 40rpx 0 54rpx;
.ul{
display: flex;
justify-content: space-around;
.li{
&::after {
border: none;
}
.icon{
display: block;
width: 92rpx;
height: 92rpx;
}
.label{
padding-top: 22rpx;
font-size: 24rpx;
line-height: 34rpx;
color: #333333;
display: block;
}
}
}
}
.btn-close{
background-color: #fff;
padding: 30rpx 0;
font-size: 26rpx;
color: #333;
}
}
.share-h5{
padding:0 20rpx;
display: flex;
justify-content: center;
.text{
line-height: 100rpx;
font-size: 30px;
.icon{
background-color: #333;
border-radius: 50%;
display: inline-block;
width: 40rpx;
height: 40rpx;
text-align: center;
line-height: 40rpx;
margin: 0 10rpx;
}
}
}
.share-button::after {
border: none;
}
</style>

388
components/AliHbPay/index.vue

@ -0,0 +1,388 @@
<!--
* @FileDescription: 阿里花呗分期支付
* @Author: kahu
* @Date: 2022/11/21
* @LastEditors: kahu
* @LastEditTime: 2022/11/21
-->
<template>
<view class="ali-hb-pay-content">
<u-popup
class="pay-type-popup"
v-model="showPopup"
mode="bottom"
border-radius="14"
close-icon-pos="top-right"
close-icon-size="20"
>
<view class="pay-type-item">
<radio-group
@change="payTypeChange"
v-model="flowerObj.paymentMode"
>
<view class="pay-type-radio">
<view class="pay-type-img">
<img
class="pay-type-img-inner"
src="https://ceres.zkthink.com/static/images/alipay.png"
/>
</view>
<label class="pay-type-label">支付宝支付</label>
<radio
class="pay-type-radio-item"
style="transform:scale(0.7)"
:checked="flowerObj.paymentMode === '2'"
value="2"
/>
</view>
<view class="pay-type-radio">
<view class="pay-type-img">
<img
class="pay-type-img-inner"
src="https://ceres.zkthink.com/static/images/huabei.png"
/>
</view>
<label class="pay-type-label">花呗分期</label>
<radio
class="pay-type-radio-item"
style="transform:scale(0.7)"
:disabled="totalPrice < 0.03"
:checked="flowerObj.paymentMode === '3'"
value="3"
/>
</view>
</radio-group>
<view class="huabei-detail" v-if="flowerObj.paymentMode==='3'">
<radio-group
@change="handleChangePeriods"
v-model="flowerObj.hbByStagesPeriods"
>
<view class="period-radio" v-for="stages in flowerObj.hbByStagesList">
<view class="period-amount">
<label class="period-each"> {{ stages.price }}x{{ stages.numberOfStages }}</label>
<label class="period-each-charge">手续费{{ stages.serviceCharge}}/</label>
</view>
<radio
class="period-type-radio-item"
style="transform:scale(0.7)"
:disabled="stages.disabled"
:checked="Number(flowerObj.hbByStagesPeriods) === stages.numberOfStages"
:value="stages.numberOfStages+''"
/>
</view>
</radio-group>
</view>
</view>
<view class="paytype-confirm">
<view
class="fenqi-total-amount"
v-if="totalPrice >= 0.03 && flowerObj.paymentMode === '3'"
>
<label class="fenqi-all">分期总额 {{ totalPrice }}</label>
<label class="charge-fee-all">手续费 {{ flowerObj.hbServiceChargeTotal }}</label>
</view>
<view
class="fenqi-total-amount"
v-if="flowerObj.paymentMode === '2'"
>
<label class="order-amount">订单总额 {{ totalPrice }}</label>
</view>
<view class="fenqi-confirm">
<text
class="btn active"
@click="handleAliPayConfirm"
>确认
</text>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import NET from "../../utils/request";
import API from "../../config/api";
import { handleDoPay } from "../../utils/payUtil";
export default {
name: "AliHbPay",
data() {
return {
//
flowerObj: {
paymentMode: '2',// 1- 2- 3-
hbChargeType: 1,// 1- 2-
hbByStagesPeriods: '-1', // 3 6 12
hbByStagesList: [
{
rate: 0,
price: 0,
numberOfStages: 3,
serviceCharge: 0,
disabled: false
},
{
rate: 0,
price: 0,
numberOfStages: 6,
serviceCharge: 0,
disabled: false
},
{
rate: 0,
price: 0,
numberOfStages: 12,
serviceCharge: 0,
disabled: false
}
], // {3}{6}{12}
hbServiceChargeTotal: 0, //
},
}
},
props:{
totalPrice:{
type:Number | String,
default:()=>0
},
show:{
type:Boolean,
default:false
},
alipayInfo:{
type:Object,
default:()=>({})
}
},
computed:{
showPopup:{
get(){
return this.show
},
set(value){
this.$emit('change',value)
}
}
},
model:{
prop:'show',
event:'change'
},
mounted(){
this.getTheFlowerConfig()
},
methods: {
/**
* 获取花呗分期配置
*/
async getTheFlowerConfig() {
const {data} = await NET.request(API.GetHuabeiConfig, {}, 'GET')
const {flowerObj} = this
flowerObj.hbChargeType = data.huabeiChargeType
//
if (data.huabeiChargeType === 2) {
data.huabeiFeeRateList.forEach((rate, index) => {
flowerObj.hbByStagesList[index].rate = rate
})
}
},
/**
* 处理花呗期数选择
* @param event
*/
handleChangePeriods(event) {
this.flowerObj.hbByStagesPeriods = event
console.log(event)
this.handleHbStagesAndPrice()
},
/**
* 处理支付宝支付方式选择逻辑
* @param event
*/
payTypeChange(event) {
const flowerObj = this.flowerObj
const paymentMode = flowerObj.paymentMode = event.target.value;
if (paymentMode === '2') {
//
flowerObj.hbByStagesPeriods = '-1'
// 3 6 12
flowerObj.hbByStagesList.map(item => {
item.disabled = true
})
} else {
//
flowerObj.hbByStagesPeriods = '3'
}
this.handleHbStagesAndPrice()
},
/**
* 处理花呗价格和手续费显示
*/
handleHbStagesAndPrice() {
const {flowerObj, totalPrice} = this
if (flowerObj.paymentMode !== '3') return
flowerObj.hbByStagesList.forEach(stages => {
//
stages.price = ((totalPrice * (1 + stages.rate / 100)) / stages.numberOfStages).toFixed(2) //
stages.serviceCharge = ((totalPrice * (stages.rate / 100)) / stages.numberOfStages).toFixed(2) //
//
if (stages.numberOfStages === Number(flowerObj.hbByStagesPeriods)) {
flowerObj.hbServiceChargeTotal = (totalPrice * (stages.rate / 100)).toFixed(2)
}
// /100
if (this.totalPrice < stages.numberOfStages / 100) {
stages.disabled = true
}
})
},
/**
* 确认支付宝支付
* @return {Promise<void>}
*/
async handleAliPayConfirm() {
const payInfo = Object.assign({}, this.alipayInfo, {
'paymentMode': this.flowerObj.paymentMode,
'huabeiPeriod': this.flowerObj.hbByStagesPeriods
});
await handleDoPay.call(this, payInfo)
this.$emit('confirm',{
'paymentMode': this.flowerObj.paymentMode,
'huabeiPeriod': this.flowerObj.hbByStagesPeriods
})
}
}
}
</script>
<style
lang="scss"
scoped
>
.pay-type-item {
.pay-type-radio {
background-color: white;
border-bottom: 1upx solid #EDEDED;
margin-bottom: 20upx;
padding: 24upx 20upx 24upx 20upx;
.pay-type-img {
display: inline-block;
.pay-type-img-inner {
width: 50upx;
height: 50upx;
vertical-align: middle;
}
}
.pay-type-label {
vertical-align: middle;
margin-left: 30upx;
}
.pay-type-radio-item {
float: right;
margin-right: 20upx;
width: 50upx;
height: 50upx;
}
}
.huabei-detail {
margin-top: 20upx;
.fenqi-wenzi {
display: inline-block;
margin-left: 64upx;
}
.fenqi-amount {
display: block;
margin-left: 64upx;
margin-top: 14upx;
color: #BABBBC;
}
.fenqi-charge-fee {
float: right;
margin-right: 68upx;
color: #BABBBC;
}
.fenqi-modal {
width: 40upx;
height: 40upx;
margin-left: 20upx;
float: right;
position: relative;
top: -80upx;
}
}
}
.paytype-confirm {
height: 120upx;
padding: 0upx 108upx 0upx 32upx;
.fenqi-all {
display: inline-block;
width: 100%;
}
.fenqi-total-amount {
width: 65%;
float: left;
}
.fenqi-confirm {
float: right;
width: 160upx;
padding: 0upx 20upx;
.btn {
width: 216upx;
height: 80upx;
line-height: 80upx;
border-radius: 40upx;
font-size: 28upx;
text-align: center;
background: linear-gradient(90deg, rgba(255, 162, 0, 1), rgba(255, 121, 17, 1));
color: #fff;
display: inline-block;
margin-right: 66upx;
}
}
}
.period-radio {
margin: 30upx;
padding-right: 100upx;
width: 95%;
border-bottom: 1px solid #EFEFEF;
.period-amount {
display: inline-block;
.period-each-charge {
display: inline-block;
margin-top: 12upx;
margin-left: 6upx;
font-size: 26upx;
color: #b7b7b7;
margin-bottom: 13upx;
}
}
.period-each {
display: block;
}
.period-type-radio-item {
float: right;
}
}
</style>

320
components/CashierList/index.vue

@ -0,0 +1,320 @@
<!--
* @FileDescription: 收银台
* @Author: kahu
* @Date: 2022/11/21
* @LastEditors: kahu
* @LastEditTime: 2022/11/21
-->
<template>
<view class="cashier-list-content">
<u-radio-group
v-model="paymentMode"
placement="row"
iconPlacement="right"
@change="handleChangePaymentMode"
>
<view
class="cashier"
v-for="payment in paymentList"
:key="payment.id"
>
<view class="cashier-item" @click="handleChangePaymentMode(payment.paymentMode,payment.disabled)"
>
<view class="icon-text">
<image
class="pay-type-img-inner"
:src="payment.icon"
mode="widthFix"
/>
{{ payment.label }}
<span v-if="paymentMode===3 && paymentMode === payment.paymentMode">手续费{{ flowerObj.hbServiceChargeTotal }}</span>
</view>
<view class="radio">
<u-radio
:disabled="payment.disabled"
activeColor="#c5aa7b"
:name="payment.paymentMode"
/>
</view>
</view>
<!-- 花呗分期 -->
<view
class="ali-hb-content"
v-if="paymentMode===3 && paymentMode === payment.paymentMode"
>
<u-radio-group
v-model="flowerObj.hbByStagesPeriods"
placement="row"
iconPlacement="right"
@change="handleChangePeriods"
>
<view
class="cashier"
v-for="(flowerItem,index) in flowerObj.hbByStagesList"
:key="index"
>
<view class="cashier-item" @click="handleChangePeriods(flowerItem.numberOfStages,flowerItem.disabled)">
<view class="icon-text">
{{ flowerItem.numberOfStages }}{{ flowerItem.price }}/
</view>
<view class="radio-context">
手续费{{ flowerItem.serviceCharge }}/
<u-radio
class="radio"
activeColor="#c5aa7b"
:disabled="flowerItem.disabled"
:name="flowerItem.numberOfStages"
/>
</view>
</view>
</view>
</u-radio-group>
</view>
</view>
</u-radio-group>
</view>
</template>
<script>
import NET from "../../utils/request";
import API from "../../config/api";
export default {
name: "CashierList",
props: {
totalPrice: {
type: Number,
default: () => 200
}
},
data() {
return {
paymentMode: 1, // 1 2 3
paymentList: [
{
id: 1,
label: '微信支付',
paymentMode: 1,
icon: 'https://ceres.zkthink.com/static/images/wechat_pay.png',
disabled:false
},
{
id: 2,
label: '支付宝支付',
paymentMode: 2,
icon: 'https://ceres.zkthink.com/static/images/alipay.png',
disabled:false
},
{
id: 3,
label: '花呗分期',
paymentMode: 3,
icon: 'https://ceres.zkthink.com/static/images/huabei.png',
disabled:false
}
],
//
flowerObj: {
hbChargeType: 1,// 1- 2-
hbByStagesPeriods: -1, // 3 6 12
hbByStagesList: [
{
rate: 0,
price: 0,
numberOfStages: 3,
serviceCharge: 0,
disabled: false
},
{
rate: 0,
price: 0,
numberOfStages: 6,
serviceCharge: 0,
disabled: false
},
{
rate: 0,
price: 0,
numberOfStages: 12,
serviceCharge: 0,
disabled: false
}
], // {3}{6}{12}
hbServiceChargeTotal: 0, //
},
}
},
mounted(){
this.getTheFlowerConfig()
this.handleSetDisable()
this.handleNoticeFather()
},
methods: {
/**
* 根据环境更改可选支付项
*/
handleSetDisable(){
// #ifdef MP-WEIXIN
this.paymentList[0].disabled = false
this.paymentList[1].disabled = true
this.paymentList[2].disabled = true
this.paymentMode = 1
// #endif
// #ifdef MP-ALIPAY
this.paymentList[0].disabled = true
this.paymentList[1].disabled = false
this.paymentList[2].disabled = false
this.paymentMode = 2
// #endif
// #ifdef APP-PLUS || H5
this.paymentList[0].disabled = false
this.paymentList[1].disabled = true
this.paymentList[2].disabled = true
this.paymentMode = 1
// #endif
},
/**
* 支付方式改变事件
* @param paymentMode
* @param disabled
*/
handleChangePaymentMode(paymentMode,disabled=false) {
if(disabled) return
this.paymentMode = paymentMode
const { flowerObj } = this
if ([1, 2].includes(paymentMode)) {
//
flowerObj.hbByStagesPeriods = -1
// 3 6 12
flowerObj.hbByStagesList.map(item => {
item.disabled = true
})
} else {
//
flowerObj.hbByStagesPeriods = 3
}
this.handleHbStagesAndPrice()
this.handleNoticeFather()
},
/**
* 获取花呗分期配置
*/
async getTheFlowerConfig() {
const {data} = await NET.request(API.GetHuabeiConfig, {}, 'GET')
const {flowerObj} = this
flowerObj.hbChargeType = data.huabeiChargeType
//
if (data.huabeiChargeType === 1) {
data.huabeiFeeRateList.forEach((rate, index) => {
flowerObj.hbByStagesList[index].rate = rate
})
}
console.log(flowerObj)
},
/**
* 处理花呗期数选择
* @param periods 期数
* @param disabled
*/
handleChangePeriods(periods,disable=false) {
if(disable)return
const { flowerObj } = this
flowerObj.hbByStagesPeriods = periods
this.handleHbStagesAndPrice()
this.handleNoticeFather()
},
/**
* 处理花呗价格和手续费显示
*/
handleHbStagesAndPrice() {
const {flowerObj, totalPrice} = this
if (this.paymentMode !== 3) return
flowerObj.hbByStagesList.forEach(stages => {
//
stages.price = ((totalPrice * (1 + stages.rate / 100)) / stages.numberOfStages).toFixed(2) //
stages.serviceCharge = ((totalPrice * (stages.rate / 100)) / stages.numberOfStages).toFixed(2) //
//
if (stages.numberOfStages === Number(flowerObj.hbByStagesPeriods)) {
flowerObj.hbServiceChargeTotal = (totalPrice * (stages.rate / 100)).toFixed(2)
}
// /100
this.totalPrice < stages.numberOfStages / 100?stages.disabled = true:stages.disabled = false
})
},
/**
* 通知父组件
*/
handleNoticeFather(){
const { paymentMode,flowerObj } = this
const params = {
paymentMode,
huabeiPeriod:flowerObj.hbByStagesPeriods
}
this.$emit('change',params)
}
}
}
</script>
<style
lang="scss"
scoped
>
.cashier-list-content {
width: 100%;
padding: 0rpx 15rpx;
box-sizing: border-box;
background: #fff;
.u-radio-group {
display: block !important;
}
.cashier {
border-bottom: 2rpx solid #d0d0d0;
&:last-child {
border-bottom: none
}
.cashier-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 0;
box-sizing: border-box;
position: relative;
.icon-text {
display: flex;
align-items: center;
justify-content: center;
image {
width: 50rpx;
height: 50rpx;
margin-right: 15rpx;
}
}
.radio-context{
display: flex;
align-items: center;
font-size: 14rpx;
.radio{
margin-left: 15rpx;
}
}
}
.ali-hb-content {
padding: 10rpx 20px;
box-sizing: border-box;
border-top: 2rpx solid #d0d0d0;
}
}
}
</style>

72
components/Empty/index.vue

@ -0,0 +1,72 @@
<!--
* @FileDescription: index
* @Author: kahu
* @Date: 2022/11/11
* @LastEditors: kahu
* @LastEditTime: 2022/11/11
-->
<template>
<view v-if="show" class="empty-content" :style="{
paddingTop: this.paddingTop+'rpx',
background: this.background
}">
<image :src="iconUrl" />
<p class="tips">
<slot>
暂无数据~
</slot>
</p>
</view>
</template>
<script>
export default {
name: "empty",
data() {
return {}
},
props:{
show:{
type:Boolean,
default:false
},
paddingTop:{
type:Number,
default:()=>500
},
background:{
type:String,
default:()=>'#f8f8f8'
},
iconUrl:{
type:String,
default:()=>'https://ceres.zkthink.com/static/images/searchEmpty.png'
}
},
computed:{
},
methods: {}
}
</script>
<style
lang="scss"
scoped
>
.empty-content{
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
image{
width:150rpx;
height: 150rpx;
}
.tips{
margin-top: 25rpx;
font-weight: bolder;
}
}
</style>

24
components/GlobalLoading/index.js

@ -0,0 +1,24 @@
import Vue from 'vue'
import store from "../../store";
import GlobalLoading from "./index.vue";
export function showLoading(info=''){
store.commit("SET_SHOW_LOADING",{flag:true,info})
}
export function hideLoading(){
store.commit("SET_SHOW_LOADING",{flag:false,info:''})
}
export function showLoadingAuto(info='',time = 2000){
store.commit("SET_SHOW_LOADING",{flag:true,info})
setTimeout(()=>{
store.commit("SET_SHOW_LOADING",{flag:false,info:''})
},time)
}
Vue.prototype.$showLoading = showLoading
Vue.prototype.$hideLoading = hideLoading
Vue.prototype.$showLoadingAuto = showLoadingAuto
// Vue.component("globalLoading",GlobalLoading)
// export default GlobalLoading

89
components/GlobalLoading/index.vue

@ -0,0 +1,89 @@
<template>
<view class="loading-content" v-if="loadingFlag" @touchmove.stop.prevent="moveHandle"
@click.stop.prevent="moveHandle">
<!-- 遮罩 -->
<view catchtouchmove="true" class="full-mask" v-if="false"/>
<!-- loading -->
<view class="loading-gif">
<view class="flex mask">
<image src="@/static/images/loading/loading.gif"></image>
<!-- <p> {{ loadingInfo }} </p>-->
</view>
</view>
</view>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
name: "GlobalLoading",
methods: {
moveHandle() {
return;
}
},
mounted() {
console.log("+++++++++++++++++++__++++++++++++++++++++")
console.log(this.loadingFlag, this.loadingInfo)
},
computed: {
...mapGetters(["loadingFlag", "loadingInfo"])
}
}
</script>
<style lang="scss" scoped>
.loading-content {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 9999;
//pointer-events: none;
.mask {
//background-color: rgba(75, 53, 53, 0.52);
}
.full-mask {
position: absolute;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.52);
z-index: 9998;
pointer-events: none;
}
.loading-gif {
z-index: 9999;
position: relative;
width: 100%;
height: 100%;
.flex {
width: 200rpx;
height: 200rpx;
position: absolute;
border-radius: 15rpx;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
image {
width: 150rpx;
height: 150rpx;
}
p {
color: #fff;
}
}
}
}
</style>

250
components/Loading/index.vue

@ -0,0 +1,250 @@
<!-- @auth kahu -->
<template>
<view class="loading_box mask flex-center"
@touchmove.stop.prevent="HandlePageMove">
<!-- 点动画 -->
<view class="dot_box theOuterRotation"
v-if="false">
<view class="dot_item"
v-for="item in 4"></view>
</view>
<!-- 进度条动画 -->
<view class="progress_box" v-if="false">
<view class="progress_item progress_roll_center"></view>
</view>
Loading....
</view>
</template>
<script>
export default {
name: "index",
data() {
return {}
},
onPageScroll(e) {
return false
},
mounted() {
console.log(getCurrentPages())
//#ifdef H5
//#endif
},
methods: {
HandlePageMove() {
return false
}
}
}
</script>
<style lang="scss"
scoped>
.mask {
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
color: #fff;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.loading_box {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
bottom: 0;
z-index: 9999;
/** 点动画*/
.theOuterRotation {
animation: rotate 2s ease-in-out .5s infinite normal;
}
.dot_box {
width: 80rpx;
height: 80rpx;
//background: #fff;
border-radius: 20rpx;
margin: 20rpx 0;
position: relative;
// dot
.dot_item {
width: 30rpx;
height: 30rpx;
background: #fff;
border-radius: 50%;
position: absolute;
transition: all .6s;
box-shadow: 0 0 2rpx #b4b4b4;
&:nth-child(1) {
top: 0;
left: 0;
}
&:nth-child(2) {
top: 0;
right: 0;
}
&:nth-child(3) {
bottom: 0;
right: 0;
}
&:nth-child(4) {
bottom: 0;
left: 0;
}
}
//
.dot_scale {
&:nth-child(1) {
top: 0;
left: 0;
animation: magnify 2s ease-in-out 0s infinite alternate;
}
&:nth-child(2) {
top: 0;
right: 0;
animation: magnify 2s ease-in-out 1s infinite alternate;
}
&:nth-child(3) {
bottom: 0;
right: 0;
animation: magnify 2s ease-in-out 0s infinite alternate;
}
&:nth-child(4) {
bottom: 0;
left: 0;
animation: magnify 2s ease-in-out 1s infinite alternate;
}
}
//
.dot_move {
&:nth-child(1) {
z-index: 2;
animation: moveDot 2s ease-in-out 0s infinite normal;
}
}
//
@keyframes magnify {
0% {
transform: scale(1);
background: rgba(0, 255, 228, 0.82);
}
25% {
background: #32b5cc;
}
50% {
transform: scale(1.4);
background: #73e34e;
}
75% {
background: #0ec469;
}
100% {
transform: scale(1);
background: #868686;
}
}
//
@keyframes moveDot {
0% {
top: 0;
left: 0;
background: #d0f598;
}
25% {
top: 0;
left: 100%;
transform: translateX(-100%);
background: #f5e298;
}
50% {
top: 100%;
left: 100%;
transform: translate(-100%, -100%);
background: #6bea91;
}
75% {
top: 100%;
left: 0;
transform: translateY(-100%);
background: #e84c7a;
}
100% {
top: 0;
left: 0;
}
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
}
/** 进度条动画*/
.progress_box{
width: 300rpx;
height: 25rpx;
margin: 20rpx 0;
border-radius: 25rpx;
background-color: #fff;
position: relative;
overflow: hidden;
.progress_item{
width: 0%;
height: 100%;
background: #f68686;
border-radius: 25rpx;
}
.progress_roll{
animation: roll 1s ease-in-out 0s infinite alternate-reverse;
}
.progress_roll_center{
width: 5%;
transition: all .6s;
margin: 0 auto;
animation: roll 1s cubic-bezier(.15,.2,.05,.4) 0s infinite alternate-reverse;
}
}
@keyframes roll {
from{
width: 5%;
}
to{
width: 100%;
}
}
}
</style>

54
components/NoMore/index.vue

@ -0,0 +1,54 @@
<!--
* @FileDescription: index.vue
* @Author: kahu
* @Date: 2022/11/21
* @LastEditors: kahu
* @LastEditTime: 2022/11/21
-->
<template>
<view class="no-more-content" v-if="show">
<view class="line" />
<view class="text">
<slot>没有更多了</slot>
</view>
<view class="line" />
</view>
</template>
<script>
export default {
name: "NoMore",
data() {
return {}
},
props:{
show:{
type:Boolean,
default:false
}
},
methods: {}
}
</script>
<style
lang="scss"
scoped
>
.no-more-content{
margin-top: 35rpx;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
.line{
width: 20vw;
height: 2rpx;
background-color: #808080;
}
.text{
color: #808080;
margin: 0 50rpx;
}
}
</style>

200
components/Skeleton/index.vue

@ -0,0 +1,200 @@
<template>
<view v-if="loading" :style="{
width: windowWinth + 'px',
height: windowHeight + 'px',
backgroundColor: bgColor,
position: 'absolute',
left: left + 'px',
top: top + 'px',
zIndex: 100,
overflow: 'hidden'
}"
@touchmove.stop.prevent>
<view v-for="(item, index) in RectNodes" :key="$u.guid()" :class="[animation ? 'skeleton-fade' : '']" :style="{
width: item.width + 'px',
height: item.height + 'px',
backgroundColor: elColor,
position: 'absolute',
left: (item.left - left) + 'px',
top:(item.top - top)<0?(item.top - top +windowHeight-80)+ 'px':(item.top - top) + 'px'
}"></view>
<view v-for="(item, index) in circleNodes" :key="$u.guid()" :class="animation ? 'skeleton-fade' : ''" :style="{
width: item.width + 'px',
height: item.height + 'px',
backgroundColor: elColor,
borderRadius: item.width/2 + 'px',
position: 'absolute',
left: (item.left - left) + 'px',
top:(item.top - top)<0?(item.top - top +windowHeight-80)+ 'px':(item.top - top) + 'px'
}"></view>
<view v-for="(item, index) in filletNodes" :key="$u.guid()" :class="animation ? 'skeleton-fade' : ''" :style="{
width: item.width + 'px',
height: item.height + 'px',
backgroundColor: elColor,
borderRadius: borderRadius + 'rpx',
position: 'absolute',
left: (item.left - left) + 'px',
top:(item.top - top)<0?(item.top - top +windowHeight-80)+ 'px':(item.top - top) + 'px'
}">
</view>
</view>
</template>
<script>
/**
* skeleton 骨架屏
* @description 骨架屏一般用于页面在请求远程数据尚未完成时页面用灰色块预显示本来的页面结构给用户更好的体验
* @tutorial https://www.uviewui.com/components/skeleton.html
* @property {String} el-color 骨架块状元素的背景颜色默认#e5e5e5
* @property {String} bg-color 骨架组件背景颜色默认#ffffff
* @property {Boolean} animation 骨架块是否显示动画效果默认false
* @property {String Number} border-radius u-skeleton-fillet类名元素对应的骨架块的圆角大小单位rpx默认10
* @property {Boolean} loading 是否显示骨架组件请求完成后将此值设置为false默认true
* @example <u-skeleton :loading="true" :animation="true"></u-skeleton>
*/
export default {
name: "u-skeleton",
props: {
// rgb
elColor: {
type: String,
default: '#e5e5e5'
},
//
bgColor: {
type: String,
default: '#ffffff'
},
//
animation: {
type: Boolean,
default: false
},
// u-skeleton-fillet
borderRadius: {
type: [String, Number],
default: "10"
},
// true-false-
loading: {
type: Boolean,
default: true
}
},
data() {
return {
windowWinth: 750, //
windowHeight: 1500, //
filletNodes: [], //
circleNodes: [], //
RectNodes: [], //
top: 0,
left: 0,
}
},
methods: {
//
selecterQueryInfo() {
//
// 使in(this)
let query = '';
// #ifdef MP-WEIXIN
query = uni.createSelectorQuery().in(this.$parent);
// #endif
// #ifndef MP-WEIXIN
query = uni.createSelectorQuery()
// #endif
query.selectAll('.u-skeleton').boundingClientRect().exec((res) => {
this.windowHeight = res[0][0].height;
this.windowWinth = res[0][0].width;
res[0][0].bottom = res[0][0].height
this.top = res[0][0].bottom - res[0][0].height;
this.left = res[0][0].left;
});
//
this.getRectEls();
//
this.getCircleEls();
//
this.getFilletEls();
},
//
getRectEls() {
let query = '';
// 使in(this)
// #ifdef MP-WEIXIN
query = uni.createSelectorQuery().in(this.$parent);
// #endif
// #ifndef MP-WEIXIN
query = uni.createSelectorQuery()
// #endif
query.selectAll('.u-skeleton-rect').boundingClientRect().exec((res) => {
this.RectNodes = res[0];
});
},
//
getFilletEls() {
let query = '';
// 使in(this)
// #ifdef MP-WEIXIN
query = uni.createSelectorQuery().in(this.$parent);
// #endif
// #ifndef MP-WEIXIN
query = uni.createSelectorQuery()
// #endif
query.selectAll('.u-skeleton-fillet').boundingClientRect().exec((res) => {
this.filletNodes = res[0];
});
},
//
getCircleEls() {
let query = '';
// 使in(this)
// #ifdef MP-WEIXIN
query = uni.createSelectorQuery().in(this.$parent);
// #endif
// #ifndef MP-WEIXIN
query = uni.createSelectorQuery()
// #endif
query.selectAll('.u-skeleton-circle').boundingClientRect().exec((res) => {
this.circleNodes = res[0];
});
}
},
//
mounted() {
//
let systemInfo = uni.getSystemInfoSync();
this.windowHeight = systemInfo.windowHeight;
this.windowWinth = systemInfo.windowWidth;
this.selecterQueryInfo();
}
}
</script>
<style lang="scss" scoped>
.skeleton-fade {
width: 100%;
height: 100%;
background: rgb(194, 207, 214);
animation-duration: 1.5s;
animation-name: blink;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
@keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0.4;
}
100% {
opacity: 1;
}
}
</style>

633
components/activities/combinedSales.vue

@ -0,0 +1,633 @@
<template>
<view class="group-list" v-if="selectComposeData && selectComposeData.length > 0">
<view class="group-warp">
<view class="title">
<label>
<image class="title-img" src="https://ceres.zkthink.com/static/images/combinationIcon.png" alt="组合销售" mode="widthFix"></image>
</label>
<view class="price-text">
组合价¥{{composePrice}}
</view>
</view>
<view>
<scroll-view class="tabs-nav" scroll-x="true">
<view class="ul">
<view v-for="(item,index) in selectComposeData" :key="index" class="li" :class="tabIndex===index && 'on'" @click="tabChange(index)">
{{ item.composeName }}</view>
</view>
</scroll-view>
<view class="tabs-item" v-for="(item,index) in selectComposeData" :key="index" :class="tabIndex===index && 'on'">
<swiper class="swiper pro-box" :indicator-dots="false" :autoplay="true" :display-multiple-items="item.composeProductInfoList.length < 3?item.composeProductInfoList.length:3" @change="swiperChange" :disable-touch="item.composeProductInfoList.length <= 3">
<swiper-item class="pro-item-warp" v-for="(itemJ,indexJ) in item.composeProductInfoList" :key="indexJ" >
<view class="pro-item-inner">
<view class="pro-item">
<view class="pro-item-img">
<image class="img" :src="itemJ.productImage"></image>
</view>
<view class="pro-item-info">
<h3 class="name">
{{itemJ.productName}}
</h3>
<view class="sku" @click.stop="changeSkuItemValue(itemJ, indexJ)">
<view class="text">{{itemJ.skuItem.skuName}}</view>
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<view class="swiper-dots" v-if='item.composeProductInfoList.length > 3'>
<text :class="{'dot-active':swiperCurrent === index,'dot': true}"
v-for="(dot, index) in item.composeProductInfoList.length - 2"
:key="index"
></text>
</view>
</view>
<view class="btn-buy" @click="doBuy">立即购买</view>
</view>
</view>
<!-- 商品详情 -->
<u-popup v-model="goodsDetailShowFlag" mode="bottom" border-radius="14">
<view class="goosDetailshow-box">
<view class="detailImg-box flex-row-plus">
<image class="detailImg" :src="selectedSku.image"></image>
<view class="flex-column-plus mar-left-40">
<view class="font-color-C5AA7B">
<label class="fs24">¥</label>
<label class="fs36 mar-left-10"
v-text="getPrice(selectedSku)"></label>
</view>
<label class="fs24 font-color-999 mar-top-20">库存 {{selectedSku.stockNumber}} </label>
<label class="fs24 mar-top-20">已选</label>
</view>
</view>
<view class="color-box flex-column-plus">
<view v-for="(attritem,index) in skuProData.names" :key="index" class="skuStyle">
<label class="fs24 font-color-999">{{attritem.skuName}}</label>
<view class="colorName-box">
<view class="pad-bot-30" v-for="(attrRes, resIndex) in attritem.values" :key="resIndex">
<view class="colorName"
:class="{'colorName-on' : getselectedAttrVal(attritem.nameCode) == attrRes.valueCode}"
@click="nameCodeValueCodeClick(attritem.nameCode, attrRes.valueCode, true)">
{{attrRes.skuValue}}
</view>
</view>
</view>
</view>
</view>
<!-- <view class="goodsNum-box flex-row-plus flex-sp-between" :class="{'bottom-line' :supportHuabei}">-->
<!-- <label class="font-color-999 fs24">数量</label>-->
<!-- <view class="goodsNum">-->
<!-- <text class="subtract" @click="updateNumSub()">-</text>-->
<!-- <text class="goodsNumber" v-model="buyNum">{{buyNum}}</text>-->
<!-- <text class="add" @click.stop="-->
<!-- ()">+</text>-->
<!-- </view>-->
<!-- </view>-->
<view class="goosDetailbut-box flex-items-plus">
<!-- <button type="default" @click="goodsDateils(shopId,productId,skuId)" >查看详情</button>-->
<button type="default" class="submitBtn" @click="submitBtn()">确认</button>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import NET from "../../utils/request";
import API from "../../config/api";
export default {
name: "combinedSales",
props: {
pid: {
type: String,
default: ''
},
productData: {
type: Object,
default: ()=>{}
}
},
data () {
return {
skuShowFalg: false,
tabIndex: 0,
swiperCurrent: 0,
selectComposeData: [],
curProIndex: 0,
selectedSku: [],
selectedAttr: [],
skuProData: {},
goodsDetailShowFlag: false,
composePrice: 0
}
},
mounted() {
this.getSelectCompose()
},
methods:{
//
tabChange(index){
this.tabIndex = index
this.calculatePrice()
},
//
swiperChange(e) {
this.swiperCurrent = e.detail.current;
},
//
getSelectCompose() {
NET.request(API.selectCompose, {
productId: this.pid
},
"GET").then(res => {
this.selectComposeData = res.data
for(let i=0;i< this.selectComposeData.length;i++) {
let proList = this.selectComposeData[i].composeProductInfoList
for (let j = 0; j < proList.length; j++) {
proList[j].skuItem = proList[j].composeSkuInfoList[0]
}
}
this.calculatePrice()
}).catch(res => {
})
},
//
changeSkuItemValue(item,index) {
this.curProIndex = index
uni.showLoading({
mask: true,
title: '加载中...'
})
NET.request(API.QueryProductDetail, {
shopId: this.productData.shopId,
productId: item.productId,
skuId: item.skuItem.skuId,
terminal: 1
},
"GET").then(res => {
uni.hideLoading()
this.skuProData = res.data
// console.log(this.skuProData,'this.skuProData', res.data)
//productData.names
const mapKeys = Object.keys(this.skuProData.map)
if (mapKeys.length === 1 && mapKeys[0] === '单款项') {
this.skuProData.names[0].values.push({
skuValue: '单款项',
valueCode: '单款项'
})
}
//sku
for (var key in this.skuProData.map) {
let skuImage = this.skuProData.map[key].image
if (!skuImage) {
this.skuProData.map[key].image = this.skuProData.images[0]
}
}
this.goodsDetailShowFlag = true
this.selectBySkuId(item.skuItem.skuId)
}).catch(res => {
uni.hideLoading()
})
},
selectBySkuId(skuId) {
if (skuId) {
let mapinfo = this.skuProData.map
let flag = true
for (var key in mapinfo) {
if (parseInt(mapinfo[key].skuId) === parseInt(skuId)) {
flag = false
this.selectedSku = mapinfo[key]
// sku
const valueCodeList = key.split(',')
this.selectedAttr = []
this.skuProData.names.forEach(attr => {
for (var index in attr.values) {
let valueCode = attr.values[index].valueCode
if (valueCodeList.includes(valueCode)) {
this.nameCodeValueCodeClick(attr.nameCode, valueCode, false)
break
}
}
})
break
}
}
//
if(flag){
for (var key in mapinfo) {
console.log(key,'key')
this.selectedSku = mapinfo[key]
break
}
}
}
},
nameCodeValueCodeClick(nameCode, valueCode, reSelectSku) {
this.selectedAttr[nameCode] = valueCode
console.log(this.selectedAttr, 'this.selectedAttr')
if (reSelectSku) {
let attrList = []
for (var key in this.selectedAttr) {
attrList.push(this.selectedAttr[key])
}
const attrkey = attrList.join(',')
let mapinfo = this.skuProData.map
for (var key in mapinfo) {
if (attrkey === key) {
this.selectedSku = mapinfo[key]
}
}
}
this.$forceUpdate(); //
},
//
submitBtn() {
console.log(this.selectedSku,'this.selectedSku')
const curPro = this.selectComposeData[this.tabIndex].composeProductInfoList[this.curProIndex]
for(let i=0;i<curPro.composeSkuInfoList.length;i++){
if(curPro.composeSkuInfoList[i].skuId === this.selectedSku.skuId){
this.selectedSku.skuName = curPro.composeSkuInfoList[i].skuName
}
}
curPro.skuItem = this.selectedSku
this.calculatePrice()
this.goodsDetailShowFlag = false
},
//
calculatePrice(){
const proList = this.selectComposeData[this.tabIndex].composeProductInfoList,composeType= this.selectComposeData[this.tabIndex].composeType,promote= this.selectComposeData[this.tabIndex].promote
let total = 0
for(let i=0;i<proList.length;i++){
total += this.getPrice(proList[i].skuItem)
}
switch (composeType){
case 1:
this.composePrice = promote.toFixed(2)
break
case 2:
this.composePrice = (total - promote).toFixed(2)
break
case 3:
this.composePrice = parseFloat(total * promote / 10).toFixed(2)
break
}
console.log(total, this.composePrice, 'total')
},
//
getPrice(item){
// 0- 1- 2- 3- 4- 5- 6- 7- 8- 9-
if(item.activityType){
if(item.activityType === 0 || item.activityType === 6 || item.activityType === 7){
return item.price
} else {
return item.originalPrice
}
} else {
return item.price
}
},
//
doBuy(){
let addCart = []
let shopObj = {}
shopObj["shopId"] = this.productData.shopId
shopObj["composeId"] = this.selectComposeData[this.tabIndex].composeId
shopObj["skus"] = []
let proList = this.selectComposeData[this.tabIndex].composeProductInfoList
let len2 = proList.length
for (let j = 0; j < len2; j++) {
let skusObj = {}
skusObj["number"] = 1
skusObj["skuId"] = proList[j].skuItem.skuId
shopObj.skus.push(skusObj)
}
addCart.push(shopObj)
uni.setStorageSync('skuItemDTOList', addCart)
uni.navigateTo({
url: '../../pages_category_page1/orderModule/orderConfirm?type=1'
})
},
getselectedAttrVal(item){
return this.selectedAttr[item]
}
}
}
</script>
<style lang="scss" scoped>
.group-list{
padding: 10upx 20upx 60upx;
border-top: 12upx solid #F8F8F8;
.group-warp{
height: 680upx;
background: #333333;
box-shadow: 0 20upx 30upx rgba(0, 0, 0, 0.3);
opacity: 1;
border-radius: 20upx;
}
.title{
display: flex;
align-items:center;
position: relative;
justify-content: space-between;
padding: 32upx 0 20upx 30upx;
.title-img{
width: 203upx;
}
.price-text{
padding: 0 34upx;
margin-right: 10upx;
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;
}
}
}
.tabs-nav{
padding: 0 10upx;
margin-bottom: 20upx;
.ul{
display: flex;
.li{
//flex: 1 0 auto;
text-align: center;
font-size: 26rpx;
color: #999;
position: relative;
padding: 12px 40px;
word-break: keep-all;
&:first-child{
margin-left: 0;
}
&.on{
color: #FFEBC4;
&:after{
content: '';
width: 100%;
height: 2rpx;
background: #FFEBC4;
position: absolute;
left: 0;
bottom: 0;
}
}
}
}
}
.tabs-item{
display: none;
&.on{
display: block;
}
}
.pro-box{
height: 318upx;
padding: 0 2upx 20upx;
.pro-item-inner{
padding: 0 8upx;
display: flex;
justify-content: center;
}
.pro-item{
width: 219upx;
background: #FFFFFF;
padding: 10upx;
height: 318upx;
.pro-item-img{
width: 100%;
height: 160upx;
.img{
width: 100%;
height: 100%;
object-fit: contain;
}
}
.pro-item-info{
.name{
font-size: 24upx;
line-height: 34upx;
color: #333333;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
text-align: center;
font-weight: normal;
margin: 8upx 0 26upx;
}
.sku{
width: 180upx;
height: 50upx;
margin: 0 auto;
line-height: 50upx;
border: 2upx solid #E4E5E6;
background: url("https://ceres.zkthink.com/static/images/arrow-suk-select.png") no-repeat right center / 60upx 60upx;
.text{
font-size: 24upx;
color: #999;
padding-left: 20upx;
width: 126px;
text-overflow:ellipsis;
white-space: nowrap;
}
}
}
}
}
.swiper-dots{
display: flex;
justify-content: center;
.dot{
display: block;
width: 24upx;
height: 4upx;
background: #FFFFFF;
opacity: 0.5;
border-radius: 2upx;
margin: 0 20upx;
&.dot-active{
opacity: 1;
}
}
}
}
.btn-buy{
width: 688upx;
height: 84upx;
//border: 2upx solid rgba(0, 0, 0, 0);
background: linear-gradient(88deg, #C5AA7B 0%, #FFEBC4 100%);
font-size: 28upx;
color: #333;
line-height: 84upx;
margin: 30upx auto 0;
text-align: center;
}
.goosDetailshow-box {
.detailImg-box {
margin-top: 30rpx;
margin-left: 30rpx;
border-radius: 10rpx;
border-bottom: 1rpx solid #EDEDED;
padding-bottom: 20rpx;
width: 690rpx;
.detailImg {
width: 180rpx;
height: 180rpx;
}
}
.color-box {
padding: 30rpx 30rpx;
border-bottom: 1rpx solid #EDEDED;
width: 690rpx;
.skuStyle{
padding: 20rpx 0;
}
.skuStyle:nth-child(2) {
border-top: 1px solid #F3F4F5;
}
.colorName-box {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-items: center;
margin-top: 30rpx;
margin-left: -30rpx;
.colorName-on {
background-color: #FFE5D0;
color: #C5AA7B;
margin-left: 30rpx;
padding: 10rpx 32rpx;
border-radius: 28rpx;
border: 1rpx solid #C5AA7B;
font-size: 26rpx;
text-align: center;
z-index: 1;
}
.colorName {
background-color: #F5F5F5;
margin-left: 30rpx;
padding: 10rpx 32rpx;
border-radius: 28rpx;
font-size: 26rpx;
z-index: 2;
}
}
}
.modelNum-box {
padding: 30rpx 30rpx;
border-bottom: 1rpx solid #EDEDED;
width: 690rpx;
.modelNumName-box {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-items: center;
margin-top: 30rpx;
margin-left: -30rpx;
.modelNumName-on {
background-color: #FFE4D0;
color: #C5AA7B;
margin-left: 30rpx;
padding: 10rpx 32rpx;
border-radius: 28rpx;
border: 1rpx solid #C5AA7B;
font-size: 26rpx;
text-align: center;
}
.modelNumName {
background-color: #F5F5F5;
margin-left: 30rpx;
padding: 10rpx 32rpx;
border-radius: 28rpx;
font-size: 26rpx;
}
}
}
.goodsNum-box {
padding: 30rpx 30rpx;
width: 690rpx;
padding-bottom: 140rpx;
.goodsNumber {
text-align: center;
border: 1rpx solid #999999;
padding: 3rpx 20rpx;
}
.subtract {
border: 1rpx solid #999999;
padding: 3rpx 20rpx;
margin-right: -1rpx;
}
.add {
border: 1rpx solid #999999;
padding: 3rpx 20rpx;
margin-left: -1rpx;
}
}
.goosDetailbut-box {
.joinShopCartBut {
width: 343rpx;
height: 80rpx;
background-color: #FFC300;
color: #FFFEFE;
font-size: 28rpx;
line-height: 80rpx;
text-align: center;
margin-left: 30rpx;
}
.buyNowBut {
width: 343rpx;
height: 80rpx;
border-radius: 0 40rpx 40rpx 0;
background-color: #FF6F00;
color: #FFFEFE;
font-size: 28rpx;
line-height: 80rpx;
text-align: center;
}
}
.submitBtn {
width: 342rpx;
height: 100rpx;
line-height: 100rpx;
font-size: 28rpx;
border: 1px solid;
border-radius: 0;
color: #FFEBC4;
background: #333333;
margin: 20rpx 0;
}
}
</style>

430
components/adWindow.vue

@ -0,0 +1,430 @@
<template>
<view v-if="visible">
<view v-if="adInfo.jumpType === 3 && couponList && couponList.length> 0"
class="mask mask-coupon ad-coupons"
@touchmove.stop.prevent="moveHandle">
<view class="ad-box-warp">
<view class="ad-boxs">
<image class="img"
:src="adInfo.popupImg"
></image>
<view class="coupon-list">
<scroll-view :scroll-top="0"
class="scrollBox"
scroll-y="true">
<view class="item"
v-for="(item, index) in couponList"
:key="index">
<view class="leftBox borderBox">
<view class="boxTop"></view>
<view class="boxCent"></view>
<view class="boxBottom"></view>
</view>
<view class="centerBox">
<view class="money">
<text class="num"
:class="[item.discountMode ===1?'num-minus':'num-discount']">{{ item.reduceMoney }}
</text>
<text class="text">
{{ item.fullMoney }}元可用
</text>
</view>
<view class="text">
<text>
{{ item.activityName }}
</text>
</view>
</view>
<view class="rightBox borderBox">
<view class="boxTop"></view>
<view class="boxCent"></view>
<view class="boxBottom"></view>
</view>
</view>
</scroll-view>
</view>
<WxSendCoupon v-if="couponList && couponList.length > 0"
:couponList="couponList"
@closeAd="close">
<view class="btn-receive">一键领取</view>
</WxSendCoupon>
</view>
<view class="close-btn">
<image :src="adInfo.closeImg"
class='btn'
mode="widthFix"
@click="close()"></image>
</view>
</view>
</view>
<view v-else-if="adInfo.jumpType !== 3"
class="mask mask-coupon ad-link">
<view class="ad-box-warp">
<view class="ad-boxs"
@click="goRoll()">
<image class="img"
:src="adInfo.popupImg"
mode="widthFix"></image>
</view>
<view class="close-btn">
<image :src="adInfo.closeImg"
class='btn'
mode="widthFix"
@click="close()"></image>
</view>
</view>
</view>
</view>
</template>
<script>
import WxSendCoupon from "./wx/wxSendCoupon";
const NET = require('../utils/request')
const API = require('../config/api')
export default {
name: "adWindow",
components: {
WxSendCoupon
},
props: {
triggerCondition: {
type: Number,
default: 1
}
},
data() {
return {
visible: false,
adInfo: {},
jumpContent: {},
couponList: [],
isLogin: false,
buyerUserId: 0,
cParams: {}
};
},
methods: {
//
moveHandle() {
return
},
// 广
getAd() {
console.log(this.triggerCondition,'triggerCondition000000')
const res = uni.getStorageSync('storage_key'),
token = res.token;
setTimeout(() => {
this.buyerUserId = res.buyerUserId
this.isLogin = !!token
console.log(this.buyerUserId,this.isLogin,this.triggerCondition)
NET.request(API.GetAd, {
triggerCondition: this.triggerCondition
}, 'POST').then(res => {
console.log('123131321323', res)
if (res.data) {
this.adInfo = res.data[0]
if (this.adInfo.jumpContent) {
this.jumpContent = JSON.parse(this.adInfo.jumpContent)
}
this.visible = true
if (this.adInfo.jumpType === 3) {
this.getCoupons()
}
}
}).catch(res => {
})
}, 500)
},
//
getCoupons() {
if (this.isLogin) {
const _items = this.jumpContent.items
if (_items) {
NET.request(API.getCoupons, {
page: 1,
pageSize: 99,
ids: _items
}, 'GET').then(res => {
if (res.data) {
this.couponList = res.data.list
}
}).catch(res => {
})
}
} else {
uni.showToast({
title: '登录之后领取更多优惠',
icon: "none"
})
// uni.navigateTo({
// url: '/pages_category_page2/userModule/login'
// })
}
},
//
close() {
this.visible = false
var params = {}
if (this.isLogin) {
params.buyerUserId = this.buyerUserId
} else {
uni.getSystemInfo({
success: function (res) {
params.deviceId = res.deviceId
}
})
}
NET.request(API.adClose, params, 'POST').then(res => {
}).catch(res => {
})
},
goRoll() {
this.visible = false
console.log(this.jumpContent, 'this.jumpContent')
switch (this.adInfo.jumpType) {
case 1:
uni.navigateTo({
url: '/pages_category_page1/goodsModule/goodsDetails?shopId=' + this.jumpContent
.shopId + '&productId=' + this.jumpContent.id + '&skuId=' + this.jumpContent
.skuId
})
break
case 2:
let _id = this.jumpContent.id[this.jumpContent.id.length - 1]
uni.navigateTo({
url: `/pages_category_page1/goodsModule/goodsList?category3Id=${_id}`
})
break
case 4:
uni.navigateToMiniProgram({
appId: this.jumpContent.appId,
path: this.jumpContent.link,
success(res) {
//
}
})
case 5:
uni.navigateTo({
path: this.jumpContent.link
})
break
}
},
}
};
</script>
<style scoped
lang="scss">
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 55;
background-color: rgba(0, 0, 0, 0.7);
}
.mask-coupon {
z-index: 9999;
/*background: rgba(39, 38, 39, .15);*/
display: flex;
justify-content: center;
align-items: center;
.ad-box-warp {
width: 100%;
position: relative;
}
flex-direction: column;
.ad-boxs {
position: relative;
width: 100%;
text-align: center;
.img {
width: 70%;
}
}
.btn-receive {
width: 446rpx;
height: 84rpx;
background: #EC6F43;
border-radius: 42rpx;
display: block;
text-align: center;
font-size: 28rpx;
line-height: 84rpx;
color: #fff;
position: absolute;
bottom: 32rpx;
left: 50%;
margin-left: -223rpx;
}
.close-btn {
position: absolute;
bottom: -70rpx;
left: 50%;
margin-left: -25rpx;
.btn {
width: 50rpx;
height: 50rpx;
}
}
}
.ad-coupons {
.ad-box-warp {
width: 510rpx;
position: relative;
.ad-boxs {
min-height: 700rpx;
.img {
position: absolute;
top:0;
left:0;
width: 100%;
height: 100%;
}
}
}
.coupon-list {
width: 446rpx;
height: 40%;
overflow: auto;
position: absolute;
top: 40%;
left: 50%;
margin-left: -223rpx;
.scrollBox {
height: 450upx;
}
.item {
width: 100%;
height: 140rpx;
margin-top: 15rpx;
border-radius: 8rpx;
display: flex;
position: relative;
align-items: center;
overflow: hidden;
&:first-child {
margin-top: 0px;
}
.borderBox {
width: 32rpx;
height: 140rpx;
overflow: hidden;
.boxTop {
width: 32rpx;
height: 54rpx;
background: #FFFFFF;
}
.boxCent {
height: 36rpx;
overflow: hidden;
position: relative;
&:after {
content: '';
width: 32rpx;
height: 32rpx;
border-radius: 50%;
display: block;
position: absolute;
top: 50%;
margin-top: -47rpx;
left: -15rpx;
border: 32rpx solid #FFFFFF;
}
}
.boxBottom {
width: 32rpx;
height: 54rpx;
background: #FFFFFF;
}
}
.leftBox {
.boxCent {
&:after {
left: -50rpx;
}
}
}
.rightBox {
}
.centerBox {
display: flex;
align-items: center;
height: 140rpx;
background: #FFFFFF;
flex: 1;
}
.money {
width: 190rpx;
text-align: center;
.num {
font-size: 48rpx;
color: #EC6F43;
display: block;
&.num-minus::before {
content: '¥';
font-size: 36rpx;
}
&.num-discount::after {
content: '折';
font-size: 36rpx;
}
}
.text {
font-size: 24rpx;
color: #999;
}
}
.text {
flex: 1;
padding-right: 16rpx;
width: 0;
text {
font-size: 32rpx;
color: #333;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
</style>

84
components/basics/categoryList.vue

@ -0,0 +1,84 @@
<template>
<view class="tabs-nav-warp">
<scroll-view class="tabs-nav" scroll-x="true">
<view class="ul">
<view class="li" :class="{'on':activeTab===0}" @click="tabChange(0)">首页</view>
<view class="li" :class="{'on':activeTab===index+1}" v-for="(item,index) in categoryList" :key="index" @click="tabChange(index+1,item.classifyId)">
{{item.classifyName}}
</view>
</view>
</scroll-view>
</view>
</template>
<script>
const NET = require('@/utils/request')
const API = require('@/config/api')
export default {
name: "categoryList",
data () {
return {
activeTab: 0,
categoryList: []
}
},
mounted () {
this.getCategoryData();
},
methods:{
tabChange (index, id) {
this.activeTab = index
this.$emit('tabChange', index, id)
},
getCategoryData(){
uni.showLoading({
title:'加载中...'
})
NET.request(API.FindCategoryListByDepth, {
}, 'GET').then(res => {
this.categoryList = res.data
uni.hideLoading()
}).catch(res => {
uni.hideLoading()
})
}
}
}
</script>
<style lang="scss" scoped>
.tabs-nav-warp{
margin-top: 20rpx;
padding:0 30rpx;
.tabs-nav{
.ul{
display: flex;
.li{
flex: 1 0 auto;
margin-left: 36rpx;
font-size: 30rpx;
color: #999999;
position: relative;
padding-bottom: 18rpx;
&:first-child{
margin-left: 0;
}
&.on{
&:after{
content: '';
width: 100%;
height: 4rpx;
background: #C5AA7B;
position: absolute;
left: 0;
bottom: 0;
}
font-weight:bold;
}
}
}
}
}
</style>

280
components/basics/categoryShow.vue

@ -0,0 +1,280 @@
<template>
<view class="goodRecommend">
<!-- 骨架屏 -->
<view class="product-list">
<view class="product-list-box" >
<view class="product-list-item-warp" v-for="(item,index) in productList" :key="index">
<view class="product-list-item" v-if="JSON.stringify(item)!=='{}'">
<view class="product-list-img" @click="jumpProductDetail(item)">
<img v-show="item.image" class="img" :src="item.image">
</view>
<view class="product-list-info u-skeleton-fillet">
<view class="product-name">{{item.productName}}</view>
<view class="flex">
<view class="shop-box" @click.stop="jumpStore(item)">
<view class="shop-name" @click="jumpProductDetail(item)">{{item.shopName}}</view>
<view class="shop-logo">
<img :src="item.shopLogo">
</view>
</view>
<view class="buy-count">{{item.users?item.users: 0}}人付款</view>
</view>
<div class="price-warp">
<!-- #ifdef MP-WEIXIN -->
<img class="iconImg" v-if="item.activityType == 1" src="../canvasShow/static/images/groupBuyIcon.png">
<img class="iconImg" v-if="item.activityType == 2" src="../canvasShow/static/images/spikeIcon.png">
<img class="iconImg" v-if="item.activityType == 4" src="../canvasShow/static/images/spikeIcon.png">
<img class="iconImg" v-if="item.activityType == 3" src="../canvasShow/static/images/discountListIcon.png">
<img class="iconImg" v-if="item.activityType == 5" src="../canvasShow/static/images/discountListIcon.png">
<img class="iconImg" v-if="item.activityType == 8" src="../canvasShow/static/images/memberCenterIcon.png">
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="iconImg" v-if="item.activityType == 1" src="../canvasShow/static/images/groupBuyIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 2" src="../canvasShow/static/images/spikeIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 4" src="../canvasShow/static/images/spikeIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 3" src="../canvasShow/static/images/discountListIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 5" src="../canvasShow/static/images/discountListIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 8" src="../canvasShow/static/images/memberCenterIcon.png"></image>
<!-- #endif -->
<div class="price">
¥ {{item.price}}
</div>
<div class="original-price">
¥ {{item.originalPrice}}
</div>
</div>
</view>
</view>
<view class="product-list-item ske-loading" v-else>
<view class="product-list-img child-loading">
<img v-show="item.image" class="img" :src="item.image">
</view>
<view class="product-list-info">
<view class="product-name child-loading" style="border-radius: 5rpx; margin-top: 10rpx;width: 100%;padding: 20rpx 0"></view>
<view class="product-name child-loading" style="border-radius: 5rpx; margin-top: 10rpx;width: 100%;padding: 20rpx 0"></view>
</view>
</view>
</view>
</view>
</view>
<view v-if="ifShow" class="emptyCart-box flex-items-plus flex-column">
<image class="emptyCart-img" src="https://ceres.zkthink.com/static/img/bgnull.png" mode="widthFix" />
<label class="font-color-999 fs26 mar-top-30">这里空空如也~</label>
</view>
</view>
</template>
<script>
const NET = require('@/utils/request')
const API = require('@/config/api')
export default {
name: "categoryShow",
props: {
categoryid: {
type: Number,
default: 0
}
},
data () {
return {
activeTab: 0,
page:1,
pageSize:10,
total: 0,
productList: [],
ifShow: false
}
},
mounted () {
this.productList = [{},{},{},{},{},{},{},{}]
this.getData();
},
methods:{
getData(){
console.log('加载了getData')
// uni.showLoading({
// mask: true,
// title:'...'
// })
if (this.total!=0&&this.productList.length>=this.total){
console.log("加载完了")
return
}
NET.request(API.getProducts, {
classifyId: this.categoryid,
page:this.page,
pageSize:this.pageSize
}, 'GET').then(res => {
this.productList = [...this.productList,...res.data.list]
this.productList = this.productList.filter(item=>JSON.stringify(item)!=='{}')
this.total = res.data.total
uni.hideLoading()
if (this.productList.length ===0) {
this.ifShow = true
}
}).catch(res => {
uni.hideLoading()
})
},
//
jumpStore(item){
uni.navigateTo({
url: `/pages_category_page1/store/index?storeId=${item.shopId}`
})
},
//
jumpProductDetail(item){
uni.navigateTo({
url: '/pages_category_page1/goodsModule/goodsDetails?shopId=' + item.shopId + '&productId=' + item.productId + '&skuId=' + item
.skuId
})
}
},
watch: {
'categoryid': {
handler(newVal, oldVal) {
this.ifShow = false
this.getData()
},
deep: true
}
},
}
</script>
<style lang="scss" scoped>
.goodRecommend {
padding-top: 20rpx;
.product-list {
position: relative;
padding: 0 13upx;
width: 100%;
//min-height: 60vh;
&-box {
display: flex;
flex-wrap: wrap;
flex-direction: row;
&.swiper{
height: 620upx;
}
}
&.product-swiper .product-list-box{
padding-left: 0;
}
&-item-warp{
margin: 0 0 20upx 0;
}
&-item {
width: 348upx;
padding: 0 7upx;
box-sizing: content-box;
}
&-img {
width: 348upx;
height: 348upx;
background-color: #d0d0d0;
border-radius: 10upx 10upx 0 0;
.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 10upx 10upx;
padding: 20upx;
label{
font-weight: normal;
}
.product-name{
font-size: 28upx;
color: #333;
display: block;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
margin-bottom: 18upx;
line-height: 40upx;
}
.flex{
display: flex;
align-items: center;
}
.shop-box{
background-color: #333333;
border-radius: 0upx 20upx 20upx 0upx;
line-height: 40upx;
display: flex;
align-items: center;
height: 40upx;
margin-right: 10upx;
float: left;
.shop-name{
font-size: 20upx;
color: #FFEBC4;
padding: 0 8upx 0 12upx;
line-height: 40upx;
display: inline-block;
float: left;
max-width: 170rpx;
white-space: nowrap;
overflow:hidden;
text-overflow:ellipsis;
}
.shop-logo{
border: 2upx solid #707070;
border-radius: 50%;
overflow: hidden;
float: right;
img{
width: 34upx;
height: 34upx;
display: block;
}
}
}
.buy-count{
color: #C5AA7B;
font-size: 20upx;
border: 2upx solid #E4E5E6;
line-height: 36upx;
padding: 0 5upx;
}
.price-warp{
display: flex;
align-items: baseline;
line-height: 56upx;
.iconImg {
width: 58rpx;
height: 36rpx;
margin-right: 10rpx;
}
.price{
color: #C83732;
font-size: 40upx;
margin-right: 20upx;
}
.original-price{
font-size: 24upx;
color: #ccc;
text-decoration: line-through;
}
}
}
}
.emptyCart-box {
margin-top: 70rpx;
.emptyCart-img {
width: 216rpx;
height: 156rpx;
}
}
}
</style>

24
components/canvasShow/basics/assistDiv.vue

@ -0,0 +1,24 @@
<template>
<div class="div" :style="{backgroundColor:componentContent.bgColor,height:componentContent.height + 'rpx'}"></div>
</template>
<script>
export default {
name: 'assistDiv',
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
}
}
</script>
<style scoped>
.div{
width: 100%;
}
</style>

107
components/canvasShow/basics/banner.vue

@ -0,0 +1,107 @@
<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>
import {funMixin} from '../config/mixin'
export default {
name: 'cereBanner',
mixins: [funMixin],
data () {
return {
bannerHeight: 0,
swiperCurrent: 0
}
},
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
},
mounted() {
this.bannerHeight = this.componentContent.height
this.$forceUpdate() //
},
computed: {
bannerList: function () {
console.log(this.componentContent)
return this.componentContent.bannerData.filter(function (item) {
return item.bannerUrl
})
}
},
methods:{
swiperChange(e) {
this.swiperCurrent = e.detail.current;
}
}
}
</script>
<style lang="scss" scoped>
.banner{
position: relative;
.banner-item{
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>

131
components/canvasShow/basics/brandList.vue

@ -0,0 +1,131 @@
<template>
<div class="brand-list warp" :class="'terminal' + terminal">
<h2 class="hom-title" :style="{textAlign:componentContent.textAlign}">{{componentContent.title}}</h2>
<div class="content-warp">
<div class="ul clearfix">
<div class="li" v-for="(item, index) in componentContent.imgList" :key="index">
<a class="item a-link" @click="jumpLink(item.linkObj)">
<div class="imgBox">
<img :src="item.imgData" v-show="item.imgData" :alt="item.title">
</div>
<h4 class="h4">{{item.title}}</h4>
</a>
</div>
</div>
</div>
</div>
</template>
<script>
import {funMixin} from '../config/mixin'
export default {
name: 'brandList',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
}
}
</script>
<style lang="scss" scoped>
.brand-list{
color: #fff;
padding: 20upx 0;
.hom-title{
font-size: 22upx;
color: #333;
line-height: 1em;
margin-bottom: 23upx;
font-weight: bold;
}
.content-warp{
display: flex;
}
.first{
width: 24%;
padding-top: 10upx;
.item{
background-color: #7A8594;
height: 336upx;
display: flex;
flex-direction: column;
justify-content: center;
.h3{
font-size: 30upx;
line-height: 46upx;
margin-bottom: 10upx;
}
}
}
.ul{
width: 100%;
.li{
width: 25%;
float: left;
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;
}
.h4{
font-size: 18upx;
color: #333333;
text-align: center;
height: 40upx;
line-height: 40upx;
}
.p{
font-size: 12upx;
margin: 7upx 0 12upx;
}
img {
max-width: 100%;
height: 100%;
max-height: 100%;
position: absolute;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
}
}
}
}
.terminal1,.terminal2,.terminal3{
&.brand-list{
width: 710upx;
margin: 0 auto;
.content-warp{
display: block;
}
.first{
width: 100%;
}
.ul{
width: auto;
margin-left: -15upx;
.li{
width: 50%;
padding: 15upx 0 0 15upx;
.item {
padding-left: 0;
}
}
}
}
}
</style>

109
components/canvasShow/basics/categoryList.vue

@ -0,0 +1,109 @@
<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)">
<div class="imgBox">
<img ref="getHeight" :src="item.img" v-show="item.img" :alt="item.name">
</div>
</a>
</div>
</div>
</div>
</div>
</template>
<script>
import {funMixin} from '../config/mixin'
export default {
name: 'categoryList',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
}
}
</script>
<style lang="scss" scoped>
.category-list{
padding: 20upx 0;
.hom-title{
font-size: 22upx;
color: #333;
line-height: 1em;
margin-bottom: 23upx;
font-weight: bold;
text-align: center;
}
.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;
}
img {
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>

113
components/canvasShow/basics/coupon/app/index.vue

@ -0,0 +1,113 @@
<template>
<div class="coupon">
<div class="coupon-list">
<div class="coupon-item" v-for="(item,index) in couponsData" :key="index" :class="item.state && item.state !== 3 && 'isReceive'">
<!-- #ifdef MP-WEIXIN -->
<img class="coupon-item-bg" src="../../../static/images/coupon/bg-coupon.png" v-if="item.state && item.state === 3" mode="widthFix">
<img class="coupon-item-bg" src="../../../static/images/coupon/bg-coupon2.png" v-else mode="widthFix">
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="coupon-item-bg" src="../../../static/images/coupon/bg-coupon.png" v-if="item.state && item.state === 3" mode="widthFix">
<image class="coupon-item-bg" src="../../../static/images/coupon/bg-coupon2.png" v-else mode="widthFix">
<!-- #endif -->
<div class="coupon-item-cont">
<div class="coupon-item-content">
<div class="coupon-item-price">
<div class="span" v-if="item.couponType !== 2"></div>
<div class="b" v-if="typeId !== 1">{{item.couponContent}}</div>
<div class="b" v-else>{{item.reduceMoney}}</div>
<div class="b" v-if="item.couponType == 2">折券</div>
</div>
<div class="coupon-item-date">{{item.startTime.split(' ')[0].replace(/-/g, '.')}}-{{item.endTime.split(' ')[0].replace(/-/g, '.')}}</div>
<div class="coupon-item-text">{{item.content}}</div>
</div>
<button v-if="item.state === 0" class="coupon-item-btn">已领取</button>
<button v-else-if="item.state === 1" class="coupon-item-btn">已使用</button>
<button v-else-if="item.state === 2" class="coupon-item-btn">已过期</button>
<button v-else @click="receiveCoupon(item)" class="coupon-item-btn">立即领取</button>
</div>
</div>
</div>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin]
}
</script>
<style lang="scss" scoped>
.coupon {
padding: 25upx;
&-list{
display: flex;
flex-wrap: wrap;
}
&-item{
width: 335upx;
height: 292upx;
margin-left: 28upx;
text-align: center;
position: relative;
margin-bottom: 10upx;
&-bg{
width: 100%;
height: 100%;
}
&-cont{
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
}
&:nth-child(2n+1){
margin-left: 0;
}
&-content{
text-align: center;
}
&-price{
color: #C5AA7B;
margin: 26upx 0 10upx;
.span{
display: inline;
font-size: 36upx;
line-height: 68upx;
}
.b{
display: inline;
font-size: 50upx;
line-height: 68upx;
}
}
&-date,&-text{
font-size: 20upx;
line-height: 28upx;
color: #999999;
}
&-date{
margin-bottom: 8upx;
}
&-btn{
display: inline-block;
margin: 60upx auto 0;
height: 48upx;
line-height: 48upx;
background-color: #C5AA7B;
color: #fff;
font-size: 14upx
}
&.isReceive{
&-price{
color: #999;
}
&-btn{
background-color: #ccc;
}
}
}
}
</style>

109
components/canvasShow/basics/coupon/mixin.js

@ -0,0 +1,109 @@
import api from '../../config/api'
import NET from '../../../../utils/request'
import { funMixin } from '../../config/mixin'
export const commonMixin = {
name: 'textComponent',
mixins: [funMixin],
data () {
return {
couponsData: []
}
},
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
watch: {
'componentContent': {
handler(newVal, oldVal) {
this.getData()
},
deep: true
}
},
created() {
this.getData()
},
methods: {
getData() {
const _ = this
if(_.componentContent.selectedCoupon && _.componentContent.selectedCoupon.length > 0){
let _url = ''
if(_.typeId === 1){
_url =`${api.getCoupons}?page=1&pageSize=99&ids=${_.componentContent.selectedCoupon}`
} else if(_.typeId === 3) {
_url =`${api.getShopCoupons}?page=1&pageSize=99&shopId=${_.shopId}&ids=${_.componentContent.selectedCoupon}`
}
const params = {
method: 'GET',
url: _url,
}
this.sendReq(params, (res) => {
_.couponsData = res.data.list
if(_.typeId === 1){
_.couponsData.forEach(item=>{
item.couponName = item.activityName
item.effectiveStart = item.activityStartTime
item.effectiveEnd = item.activityEndTime
})
}
if(JSON.stringify(_.componentContent.couponList) !== JSON.stringify(_.couponsData)){
_.componentContent.couponList = _.couponsData
}
})
} else {
_.couponsData = []
}
},
// 领取优惠券
receiveCoupon(item) {
const res = uni.getStorageSync('storage_key');
const token = res.token
if (token) {
var paramsData = {}
if(this.typeId === 1){
paramsData.couponId = item.couponId
} else if(this.typeId === 3) {
paramsData.shopCouponId = item.shopCouponId
paramsData.shopId = this.shopId
}
NET.request(api.takeCoupon, paramsData, 'POST').then(res => {
this.getData()
uni.showToast({
title:'领取成功',
icon:"success"
})
}).catch(res => {
if(res.data.code !== '200'){
uni.showToast({
title:res.data.message,
icon:"none"
})
}
})
} else {
uni.showToast({
title:'请先登录',
icon:"none"
})
uni.navigateTo({
url:'/pages_category_page2/userModule/login'
})
}
}
}
}

375
components/canvasShow/basics/coupon/pc/index.vue

@ -0,0 +1,375 @@
<template>
<div class="couponBox warp" :class="['terminal' + terminal,'arrange'+(componentContent.arrangeActiveIndex+1),'color'+(componentContent.colorActiveIndex+1)]">
<div class="couponListBox" v-if="componentContent.selectedCoupon">
<div class="listItemBox" v-for="(item,index) in couponsData" :key="index" :class="item.state && item.state !== 3 && 'isReceive'">
<div class="listItemBoxInner">
<div class="itemInfo">
<i class="flag" :class="'flag'+item.couponType"></i>
<div class="amount">
<b v-if="item.couponType !== 2"></b>
<span v-if="typeId !== 1">
{{item.couponContent}}
</span>
<span v-else>
{{item.reduceMoney}}
</span>
<b v-if="item.couponType == 2"></b>
</div>
<div class="couponInfo">
<p>{{item.content}}</p>
</div>
</div>
<!-- <div class="itemInfo" v-else>-->
<!-- <div class="amount">-->
<!-- <b></b><span>{{item.reduceMoney}}<i>满减券</i></span>-->
<!-- </div>-->
<!-- <div class="couponInfo">-->
<!-- <p>{{item.content}}</p>-->
<!-- </div>-->
<!-- </div>-->
<div v-if="item.state === 0" class="receiveBtn">
<span>己领取</span>
</div>
<div v-else-if="item.state === 1" class="receiveBtn">
<span>已使用</span>
</div>
<div v-else-if="item.state === 2" class="receiveBtn">
<span>已过期</span>
</div>
<div v-else class="receiveBtn" @click="receiveCoupon(item)">
<span>立即领取</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin]
}
</script>
<style lang="scss" scoped>
.couponBox {
min-height: 177px;
margin: 0 auto;
padding: 20px 0;
.couponListBox {
flex-wrap: wrap;
/**默认**/
.listItemBox {
//background-image:url('../../../static/images/coupon/border_L1.png'), url('../../../static/images/coupon/border_R1.png');
//background-repeat: no-repeat, no-repeat;
//background-position: left top, right top;
box-sizing: border-box;
margin-bottom: 20px;
.listItemBoxInner {
width: 100%;
height: 150px;
display: flex;
background-color: #FAFAFA;
align-items: center;
justify-content: space-between;
position: relative;
.flag{
display: block;
width: 71px;
height: 71px;
background-repeat: no-repeat;
position: absolute;
top: 0;
left: 0;
&.flag1{
background-image: url("../../../static/images/coupon/flag-coupon.png");
}
&.flag2{
background-image: url("../../../static/images/coupon/flag-coupon2.png");
}
}
.itemInfo {
flex: 1;
}
.amount {
max-width: 90%;
margin: 0 auto;
display: flex;
align-items: baseline;
justify-content: center;
line-height: 60px;
b {
font-size: 30px;
}
span {
font-size: 60px;
font-weight: bold;
}
i {
font-style: normal;
font-size: 18px;
margin-left: 5px;
}
}
.couponInfo {
text-align: center;
p {
display: inline-block;
padding: 0 42px;
text-align: center;
font-size: 18px;
line-height: 40px;
color: #C83732;
background: #F5E5E5;
}
}
}
.receiveBtn {
width: 72px;
margin-right: 5px;
background: #C5AA7B;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
&:before,&:after{
content: '';
display: block;
width: 25px;
height: 25px;
background-color: #fff;
position: absolute;
left: -12.5px;
border-radius: 50%;
}
&:before{
top: -12.5px;
}
&:after{
bottom: -12.5px;
}
span {
color: #FFFFFF !important;
writing-mode: vertical-lr;
font-size: 19px;
}
}
&.isReceive {
//background-image:url('../../../static/images/coupon/border_L4.png'), url('../../../static/images/coupon/border_R4.png');
.listItemBoxInner {
.flag{
&.flag1{
background-image: url("../../../static/images/coupon/flag-coupon-r.png");
}
&.flag2{
background-image: url("../../../static/images/coupon/flag-coupon2-r.png");
}
}
.itemInfo {
color: #999;
.couponInfo {
p {
color: #999;
background: #F1F1F1;
}
}
}
.receiveBtn {
cursor: auto;
background: #999;
}
}
}
}
}
@mixin cardColor($bgColor: #FF3737,$fontColor: #fff) {
.couponListBox {
.listItemBox {
.listItemBoxInner{
background: $bgColor;
}
.itemInfo {
.amount {
b {
color: #EC4B42;
}
span {
color: #EC4B42;
i {
color: #EC4B42;
}
}
}
.couponInfo {
color:#EC4B42;
}
}
.receiveBtn {
span {
color: #EC4B42;
}
}
&.cardStyle3{
.itemInfo {
.amount {
span {
color: $bgColor;
i {
color: $bgColor;
}
}
}
.couponInfo {
color:$bgColor;
}
}
}
&.cardStyle4{
border: 2px solid $bgColor;
padding: 5px;
.listItemBoxInner{
padding: 20px 15px;
height: 85px;
border: 1px solid $bgColor;
}
.itemInfo {
.amount {
span {
color: $bgColor;
i {
color: $bgColor;
}
}
}
.couponInfo {
color:$bgColor;
}
}
.receiveBtn {
border-left: 1px $bgColor dashed;
span {
color: $bgColor;
}
}
}
}
}
}
&.arrange1{
}
&.arrange2{
max-width: 100%;
.couponListBox{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.listItemBox{
width: 48%;
}
}
}
&.arrange3{
max-width: 100%;
.couponListBox{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.listItemBox{
width: 32%;
}
}
}
&.arrange4{
max-width: 100%;
.couponListBox{
display: flex;
overflow: hidden;
.listItemBox{
width: 268px;
flex: 0 0 268px;
margin:0 25px 25px 0;
&:nth-child(4n){
margin-right: 0;
}
}
}
}
//&.color1{
// .listItemBox {
// background-image:url('../../../static/images/coupon/border_L1.png'), url('../../../static/images/coupon/border_R1.png');
// .listItemBoxInner {
// border-top: 1px solid #EC4B42;
// border-bottom: 1px solid #EC4B42;
// .itemInfo {
// color: #EC4B42;
// .amount {
// border-bottom: 1px solid #EC4B42;
// }
// .couponInfo {
// p {
// color: #EC4B42;
// }
// }
// }
// .receiveBtn {
// background: #EC4B42;
// }
// }
// }
//}
&.color2{
.listItemBox {
background-image:url('../../../static/images/coupon/border_L2.png'), url('../../../static/images/coupon/border_R2.png');
.listItemBoxInner {
border-top: 1px solid #FF7800;
border-bottom: 1px solid #FF7800;
.itemInfo {
color: #FF7800;
.amount {
border-bottom: 1px solid #FF7800;
}
.couponInfo {
p {
color: #FF7800;
}
}
}
.receiveBtn {
background: #FF7800;
}
}
}
}
&.color3{
.listItemBox {
background-image:url('../../../static/images/coupon/border_L3.png'), url('../../../static/images/coupon/border_R3.png');
.listItemBoxInner {
border-top: 1px solid #86A7FF;
border-bottom: 1px solid #86A7FF;
.itemInfo {
color: #86A7FF;
.amount {
border-bottom: 1px solid #86A7FF;
}
.couponInfo {
p {
color: #86A7FF;
}
}
}
.receiveBtn {
background: #86A7FF;
}
}
}
}
}
</style>

238
components/canvasShow/basics/custom.vue

@ -0,0 +1,238 @@
<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)"><img 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) + '%': '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)"><img class="img" :src="item.src" v-if="item.src" mode="widthFix"></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {funMixin} from '../config/mixin'
export default {
name: 'customComponent',
mixins: [funMixin],
data () {
return {
}
},
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
},
methods: {
//
getItemValue (val) {
const density = parseInt(this.componentContent.density)
if (val === 0 || density === 0) {
return 0
}
return (val / density * 10000 / 100.00)//
}
}
}
</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;
}
}
.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>

300
components/canvasShow/basics/discount/app/index.vue

@ -0,0 +1,300 @@
<template>
<div class="hom-pro-list" v-if="productData.products.length">
<div class="title">
<!-- #ifdef MP-WEIXIN -->
<img class="title-img" src="../../../static/images/discount/img-title.png" alt="限时折扣" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="title-img" src="../../../static/images/discount/img-title.png" alt="限时折扣" mode="widthFix"/>
<!-- #endif -->
</div>
<div v-if="componentContent.arrangeType == '横向滑动' && productData.products.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="swiper-slide product-list-item-warp" v-for="(item,index) in productData.products.slice(0, 10)" :key="index" @click="jumpProductDetail(item)">
<div class="product-list-item">
<div class="product-list-img">
<img class="img default-img" :src="item.image">
</div>
<div class="product-list-info">
<label class="product-name">{{item.productName}}</label>
<div>
<div class="flag">
<!-- #ifdef MP-WEIXIN -->
<img class="icon" src="../../../static/images/discount/flag-discount2.png" alt="限时折扣" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="icon" src="../../../static/images/discount/flag-discount2.png" alt="限时折扣" mode="widthFix"/>
<!-- #endif -->
</div>
<label class="buy-count">剩余{{item.stockNumber}}</label>
</div>
<div class="price-warp">
<div class="price">
¥ {{item.price}}
</div>
<div class="original-price">
¥ {{item.originalPrice}}
</div>
</div>
</div>
</div>
</swiper-item>
</swiper>
<view class="swiper-dots" v-if="productData.products && productData.products.length > 2">
<text class="dot" :class="index - swiperCurrent <= 1 && index - swiperCurrent >=0 && 'dot-active'" v-for="(dot, index) in productData.products.length"
:key="index"></text>
</view>
<!-- <div class="pagination discount-pagination" slot="pagination"></div>-->
</div>
<div v-else class="product-list">
<div class="product-list-box" >
<div class="product-list-item-warp" v-for="(item,index) in productData.products" :key="index" @click="jumpProductDetail(item)">
<div class="product-list-item">
<div class="product-list-img">
<img class="img default-img" :src="item.image">
</div>
<div class="product-list-info">
<label class="product-name">{{item.productName}}</label>
<div>
<div class="flag">
<!-- #ifdef MP-WEIXIN -->
<img class="icon" src="../../../static/images/discount/flag-discount2.png" alt="限时折扣" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="icon" src="../../../static/images/discount/flag-discount2.png" alt="限时折扣" mode="widthFix"/>
<!-- #endif -->
</div>
<label class="buy-count">剩余{{item.stockNumber}}</label>
</div>
<div class="price-warp">
<div class="price">
¥ {{item.price}}
</div>
<div class="original-price">
¥ {{item.originalPrice}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<button v-show="componentContent.showMore" class="btn-more" @click="jumpDiscount(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperCurrent: 0,
}
},
methods:{
swiperChange(e) {
this.swiperCurrent = e.detail.current;
}
}
}
</script>
<style lang="scss" scoped>
.hom-pro-list{
padding: 20px 0;
.title{
text-align: center;
margin-bottom: 20upx;
.title-img{
width: 203upx;
}
}
/**多行多列**/
.product-list {
position: relative;
&-box {
display: flex;
flex-wrap: wrap;
flex-direction: row;
padding-left: 20upx;
&.swiper{
height: 620upx;
}
}
&.product-swiper .product-list-box{
margin: 0 20upx;
padding-left: 0;
}
&-item-warp{
margin: 0 0 20upx 0;
}
&-item {
width: 348upx;
padding: 0 7upx;
box-sizing: content-box;
}
&-img {
width: 348upx;
height: 348upx;
background-color: #f5f5f5;
border-radius: 10upx 10upx 0 0;
.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 10upx 10upx;
padding: 20upx;
label{
font-weight: normal;
}
.product-name{
font-size: 28upx;
color: #333;
display: block;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
margin-bottom: 18upx;
line-height: 40upx;
}
.shop-box{
background-color: #333333;
border-radius: 0px 20upx 20upx 0upx;
line-height: 40upx;
display: inline-block;
height: 40upx;
margin-right: 10upx;
.shop-name{
font-size: 20upx;
color: #FFEBC4;
padding: 0 8px 0 12upx;
}
.shop-logo{
border: 2px solid #707070;
border-radius: 50%;
overflow: hidden;
float: right;
img{
width: 34upx;
height: 34upx;
display: block;
}
}
}
.flag{
float: left;
margin-right: 20upx;
.icon{
width: 100rpx;
height: 40rpx;
display: block;
}
}
.buy-count{
color: #C5AA7B;
font-size: 20upx;
border: 2upx solid #E4E5E6;
line-height: 40upx;
padding: 0 5upx;
display: inline-block;
}
.price-warp{
display: flex;
align-items: baseline;
line-height: 56upx;
margin-top: 16upx;
.price{
color: #C83732;
font-size: 40upx;
margin-right: 20upx;
}
.original-price{
font-size: 24upx;
color: #ccc;
text-decoration: line-through;
}
}
}
//::v-deep .swiper-pagination-bullet{
// display: none;
//}
}
}
//::v-deep .uni-swiper-dots{
// display: flex;
// justify-content: center;
// padding: 10upx 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;
}
}
//.pagination{
// display: flex;
// justify-content: center;
// padding: 20upx 0;
// ::v-deep .swiper-pagination-bullet{
// width: 10upx;
// height: 10upx;
// background: #333333;
// opacity: 0.3;
// border-radius: 5upx;
// margin: 0 5upx;
// }
// ::v-deep .swiper-pagination-bullet-active{
// width: 20upx;
// height: 10upx;
// opacity: 1;
// }
//}
.btn-more {
width: 170upx;
height: 54upx;
line-height: 54upx;
border: 2upx solid #C5AA7B;
color: #C5AA7B;
font-size: 24upx;
background-color: transparent;
margin: 20upx auto 0;
display: flex;
align-items: center;
}
</style>

110
components/canvasShow/basics/discount/mixin.js

@ -0,0 +1,110 @@
// import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
// import 'swiper/css/swiper.css'
import api from '../../config/api'
import {funMixin} from '../../config/mixin'
export const commonMixin = {
name: 'discountList',
mixins: [funMixin],
data () {
return {
value: 100,
productData: {
products: []
},
count: [],
timer: null
}
},
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
// components: {
// Swiper,
// SwiperSlide
// },
// directives: {
// swiper: directive
// },
watch: {
'componentContent': {
handler(newVal, oldVal) {
this.getData()
},
deep: true
}
},
created() {
this.getData()
},
methods: {
getData() {
const _ = this
if(_.componentContent.discountId){
var _url= ''
if(this.typeId === 1){
_url= `${api.getMinDiscount}?ids=${_.componentContent.discountId}`
}
if(this.typeId === 3){
_url= `${api.getDiscounts}?shopId=${_.shopId}&ids=${_.componentContent.discountId}`
}
const params = {
method: 'GET',
url: _url,
}
this.sendReq(params, (res) => {
if(res.data.length> 0){
_.productData = res.data[0]
// 只有进行中和未开始活动, 用倒计时
if(_.productData.state !==2) {
this.timer = setInterval(()=>{
_.getTime(_.productData)
}, 1000)
}
}
})
} else {
_.productData = {
products:[]
}
}
},
getTime(info) {
const date = new Date().getTime()
const startTime = new Date(info.startTime.replace(/-/g,'/')).getTime()
const endTime = new Date(info.endTime.replace(/-/g,'/')).getTime()
if(startTime > date) {
this.countDown(startTime-date,true) // 未开始
} else {
this.countDown(endTime-date) // 进行中
}
},
countDown(time, isStart) {
const fn = (v) => v < 10 ? `0${v}` : v
const t = parseInt(time / 1000)
const text = isStart ? '开始' : '结束'
const hour = parseInt(t / 3600)
const min = parseInt((t % 3600) / 60)
const s = t % 60
this.count = [text, fn(hour), fn(min), fn(s)]
}
},
beforeDestroy() {
clearInterval(this.timer)
}
}

247
components/canvasShow/basics/discount/pc/index.vue

@ -0,0 +1,247 @@
<template>
<div class="discount">
<div class="discount-top">
<div class="discount-top-text">全场5折起</div>
<div class="discount-top-time">
<!-- {{count[0]}}-->
距离本场结束还有
<div class="time"><span>{{count[1]}}</span>:<span>{{count[2]}}</span>:<span>{{count[3]}}</span></div></div>
</div>
<div class="discount-more" :style="{backgroundImage: 'url('+ componentContent.moreBg +')'}">
<div class="discount-more-overlay">
<button class="btn-more" @click="jumpDiscount(productData)">查看全部</button>
</div>
</div>
<div class="discount-list">
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<swiper class="products-swiper" :options="swiperOption">
<swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData.products" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
<dl>
<dt><img src="../../../static/images/discount/flag-discount.png" alt="折扣价"></dt>
<dd>
¥{{item.price}}
</dd>
</dl>
</div>
</div>
</div>
</swiper-slide>
</swiper>
</div>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperOption: {
slidesPerView: 3, //
spaceBetween: 13, //
autoplay: false, //
loop: true,
pagination: {
el: '.discount-pagination'
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
}
}
}
}
</script>
<style lang="scss" scoped>
.discount{
width: 1200px;
max-width: 100%;
margin: 0 auto;
overflow: hidden;
&-top{
height: 250px;
padding-top: 96px;
margin-bottom: 15px;
background: url("../../../static/images/discount/bg-discount-top.png") no-repeat;
&-text{
background: url("../../../static/images/discount/bg-discount-top-text.png") no-repeat;
width: 176px;
height: 83px;
padding-top: 13px;
line-height: 50px;
font-size: 25px;
color: #fff;
margin: 0px auto 18px;
text-align: center;
}
&-time{
margin: 0 auto;
text-align: center;
font-size: 16px;
color: #FFEBC4;
.time{
font-size: 20px;
color: #999;
display: inline-block;
span{
display: inline-block;
line-height: 40px;
padding: 0 9px;
margin: 0 5px;
background-color: #343434;
color: #fff;
}
}
}
}
&-list{
margin-right: 303px;
position: relative;
.swiper-button-prev,.swiper-button-next{
width: 95px;
height: 95px;
position: absolute;
cursor:pointer;
top: 115px;
background-repeat: no-repeat;
&:after{
content: '';
}
}
.swiper-button-prev{
left: -22px;
background: url('../../../static/images/btn-prev2.png');
}
.swiper-button-next{
right: -22px;
background: url('../../../static/images/btn-next2.png');
}
.a-link{
cursor: pointer;
&:hover{
box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
}
.itemImgBox {
height: auto;
display: flex;
flex-direction: column;
justify-content: center;
.imgBox {
padding-bottom: 100%;
background-color: #cacaca;
position: relative;
.el-image {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
}
}
.text{
padding:25px 20px 17px;
text-align: center;
//height: 180px;
.h4{
font-size: 18px;
line-height: 24px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
color: #333333;
//max-height: 48px;
}
.p{
color: #999;
font-size: 16px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
padding-top: 18px;
position: relative;
margin-top: 8px;
&:after{
position: absolute;
top: 0;
left: 50%;
margin-left: -80px;
width: 160px;
height: 2px;
background: #F0F0F0;
content: '';
}
}
.priceBox {
dl {
display: inline-block;
min-width: 130px;
dt{
float: left;
img{
display: block;
}
}
dd{
border: 1px solid #F3F4F5;
font-size: 25px;
line-height: 34px;
color: #C83732;
margin-left: 57px;
padding: 0 10px;
}
}
span.discount {
display: block;
font-size: 18px;
line-height: 24px;
padding: 15px 0 11px;
color: #ccc;
text-decoration: line-through;
}
}
}
}
}
&-more{
width: 290px;
height: 466px;
float: right;
position: relative;
&-overlay{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.6);
display: flex;
justify-content: center;
align-items: center;
.btn-more{
width: 130px;
height: 41px;
background-color: #fff;
font-size: 18px;
color: #C5AA7B;
}
}
}
}
</style>

213
components/canvasShow/basics/group/app/index.vue

@ -0,0 +1,213 @@
<template>
<div class="group-list" v-if="productData.products&&productData.products.length>0">
<div class="group-warp">
<div class="title">
<label>
<!-- #ifdef MP-WEIXIN -->
<img class="title-img" src="../../../static/images/group/img-title.png" alt="拼团专区" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="title-img" src="../../../static/images/group/img-title.png" alt="拼团专区" mode="widthFix"/>
<!-- #endif -->
</label>
<a v-show="componentContent.showMore" class="btn-all a-link" @click="jumpGroupWorks(productData)">更多<i class="iconfont icon-arrow-right"></i></a>
</div>
<div>
<swiper class="swiper pro-box" :circular="true" :indicator-dots="false" :autoplay="true" :display-multiple-items="3" @change="swiperChange">
<swiper-item class="swiper-slide pro-item-warp" v-for="(item,index) in productData.products" :key="index" @click="jumpProductDetail(item)">
<div class="pro-item-inner">
<div class="pro-item">
<div class="pro-item-img">
<img class="img default-img" :src="item.image">
</div>
<div class="pro-item-info">
<label class="name">{{item.productName}}</label>
<div class="price">
<label class="unit">¥ </label>
<label class="val"> {{item.price}}</label>
</div>
<label class="buyCount">{{item.workUsers?item.workUsers:0}}人已拼</label>
</div>
</div>
</div>
</swiper-item>
<!-- #ifdef MP-WEIXIN -->
<swiper-item v-if="productData.products.length" class="swiper-slide pro-item-warp" v-for="item in (3 - productData.products.length)">
</swiper-item>
<!-- #endif -->
</swiper>
<view class="swiper-dots" v-if="productData.products && productData.products.length > 3">
<text class="dot" :class="index - swiperCurrent <= 2 && index - swiperCurrent >=0 && 'dot-active'" v-for="(dot, index) in productData.products.length"
:key="index"></text>
</view>
</div>
</div>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperCurrent: 0,
}
},
methods:{
swiperChange(e) {
this.swiperCurrent = e.detail.current;
}
}
}
</script>
<style lang="scss" scoped>
.group-list{
padding: 30upx 20upx 60upx;
.group-warp{
width: 710upx;
height: 528upx;
padding: 0 2upx;
background: #333333;
box-shadow: 0px 20upx 30upx rgba(0, 0, 0, 0.3);
opacity: 1;
border-radius: 20upx;
position: relative;
}
.title{
display: flex;
align-items:center;
position: relative;
padding: 40upx 0 25upx 20upx;
.title-img{
width: 189upx;
height: 34rpx;
}
.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{
height: 390upx;
display: flex;
&.swiper-disabled{
.uni-swiper-wrapper{
position: static;
}
}
.pro-item-warp{
width: 236px;
}
.pro-item{
width: 220upx;
height: 382upx;
background: #FFFFFF;
.pro-item-img{
.img{
width: 100%;
height: 220upx;
}
}
&-inner{
padding: 0 8upx;
}
.pro-item-info{
text-align: center;
padding: 0px 10upx 20upx;
.name{
font-size: 24upx;
font-weight: normal;
color: #FFEBC4;
line-height: 50upx;
background-color: #333333;
text-align: center;
margin-bottom: 18upx;
padding: 0 5px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.price{
color: #C83732;
font-size: 28upx;
font-weight: bold;
line-height: 40upx;
}
.buyCount{
font-size: 24upx;
color: #ccc;
line-height: 34upx;
font-weight: normal;
}
}
}
}
::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>

86
components/canvasShow/basics/group/mixin.js

@ -0,0 +1,86 @@
// import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
// import 'swiper/css/swiper.css'
import api from '../../config/api'
import {funMixin} from '../../config/mixin'
export const commonMixin = {
name: 'productList',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
// components: {
// Swiper,
// SwiperSlide
// },
// directives: {
// swiper: directive
// },
data () {
return {
productData: {
products: []
}
}
},
watch: {
'componentContent': {
handler(newVal, oldVal) {
this.getData()
},
deep: true
}
},
created() {
this.getData()
},
methods: {
getData() {
const _ = this
let _url = ''
if(_.typeId === 1){
const params = {
method: 'GET',
url: `${api.getAdminGroupWorks}`,
}
this.sendReq(params, (res) => {
_.productData.products = res.data
if (_.productData.products.length > 2) {
_.productData.show = true
} else {
_.productData.show = false
}
})
} else if(_.typeId === 3) {
if(_.componentContent.shopGroupWorkId){
const params = {
method: 'GET',
url: `${api.getGroupWorks}?shopId=${_.shopId}&ids=${_.componentContent.shopGroupWorkId}`,
}
this.sendReq(params, (res) => {
_.productData = res.data[0]
})
} else {
_.productData = {
products:[]
}
}
}
},
}
}

250
components/canvasShow/basics/group/pc/index.vue

@ -0,0 +1,250 @@
<template>
<div class="product-list" :class="'terminal'+terminal">
<div class="picListWarp" v-if="componentContent.arrangeType == '横向滑动'">
<div class="picList" v-if="productData.products && productData.products.length>0">
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<swiper class="products-swiper" :options="swiperOption">
<swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData.products" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
<dl>
<dt><img src="../../../static/images/group/flag-group.png" alt="拼团价"></dt>
<dd>
¥{{item.price}}
</dd>
</dl>
</div>
</div>
</div>
</swiper-slide>
</swiper>
</div>
</div>
<div v-else class="picList" >
<ul class="clearfix" :class="'imgTextNum' + componentContent.productNum" v-if="productData.products && productData.products.length>0">
<li class="item" v-for="(item,index) in productData.products.slice(0, componentContent.productRowNum * componentContent.productNum)" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
<dl>
<dt><img src="../../../static/images/group/flag-group.png" alt="拼团价"></dt>
<dd>
¥{{item.price}}
</dd>
</dl>
</div>
</div>
</div>
</li>
</ul>
</div>
<button v-show="componentContent.showMore" class="btn-more" @click="jumpGroupWorks(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperOption: {
slidesPerView: 4, //
spaceBetween: 13, //
autoplay: false, //
loop: true,
pagination: {
el: '.group-pagination'
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
}
}
}
}
</script>
<style lang="scss" scoped>
.product-list{
padding: 20px 0;
background-color: #fff;
.picListWarp{
width: 1380px;
max-width: 100%;
margin: 0 auto;
position: relative;
}
.picList{
width: 1200px;
max-width: 100%;
margin: 0 auto;
.swiper-button-prev,.swiper-button-next{
width: 50px;
height: 50px;
position: absolute;
cursor:pointer;
top: 140px;
background-repeat: no-repeat;
&:after{
content: '';
}
}
.swiper-button-prev{
left: 0;
background: url('../../../static/images/btn-prev.png');
}
.swiper-button-next{
right: 0;
background: url('../../../static/images/btn-next.png');
}
.a-link{
cursor: pointer;
&:hover{
box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
}
.itemImgBox {
height: auto;
display: flex;
flex-direction: column;
justify-content: center;
.imgBox {
padding-bottom: 100%;
background-color: #cacaca;
position: relative;
.el-image {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
}
}
.text{
padding:25px 20px 17px;
text-align: center;
//height: 180px;
.h4{
font-size: 18px;
line-height: 24px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
color: #333333;
//max-height: 48px;
}
.p{
color: #999;
font-size: 16px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
padding-top: 18px;
position: relative;
margin-top: 8px;
&:after{
position: absolute;
top: 0;
left: 50%;
margin-left: -80px;
width: 160px;
height: 2px;
background: #F0F0F0;
content: '';
}
}
.priceBox {
dl {
display: inline-block;
min-width: 130px;
dt{
float: left;
img{
display: block;
}
}
dd{
border: 1px solid #F3F4F5;
font-size: 25px;
line-height: 34px;
color: #C83732;
margin-left: 57px;
padding: 0 10px;
}
}
span.discount {
display: block;
font-size: 18px;
line-height: 24px;
padding: 15px 0 11px;
color: #ccc;
text-decoration: line-through;
}
}
}
}
ul{
margin: -15px 0 0 -15px;
display: flex;
flex-wrap: wrap;
li{
flex: 0 0 50%;
padding: 15px 0 0 15px;
width: 0;
}
}
.imgTextNum2 {
li {
flex: 0 0 50%;
}
}
.imgTextNum3 {
li {
flex: 0 0 33.33%;
}
}
.imgTextNum4 {
li {
flex: 0 0 25%;
}
}
.imgTextNum5 {
li {
flex: 0 0 20%;
}
}
}
}
.btn-more {
width: 130px;
height: 41px;
border: 2px solid #C5AA7B;
color: #C5AA7B;
font-size: 18px;
background-color: transparent;
margin: 20px auto 0;
display: block;
}
</style>

118
components/canvasShow/basics/header/app/index.vue

@ -0,0 +1,118 @@
<template>
<view class="header">
<view class="top-box">
<image v-if="componentContent.logoType === 1" class="logo"
:src="componentContent.imageUrl"
mode="heightFix"></image>
<view v-else class="h3" :style="{fontSize:componentContent.fontSizeNum+'px',fontWeight:componentContent.textFontW,color:componentContent.titColor}">{{componentContent.title}}</view>
<view class="search-btn" @click="searchPro">
<image class="search-icon"
src="https://ceres.zkthink.com/static/img/search.png"
mode="widthFix"></image>
</view>
</view>
<view class="tabs-nav-warp">
<scroll-view class="tabs-nav" scroll-x="true">
<view class="ul">
<view class="li" :class="{'on':activeTab===0}" @click="tabChange(0)">首页</view>
<view class="li" :class="{'on':activeTab===index+1}" v-for="(item,index) in classifyData" :key="index" @click="tabChange(index+1,item.id)">
{{item.categoryName}}
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
activeTab: 0
}
},
computed: {
},
methods:{
tabChange (index, id) {
this.activeTab = index
this.$emit('tabChange', index, id)
},
searchPro(key, type) {
uni.navigateTo({
url: `/pages_category_page1/search/index/index`
})
}
}
}
</script>
<style lang="scss" scoped>
.header {
.top-box {
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 30upx;
width: 100%;
.logo {
// width: 280upx;
height: 70upx;
margin-top: 0upx;
}
.search-btn {
height: 66upx;
background: rgba(255, 255, 255, 1);
border-radius: 33upx;
display: flex;
flex-direction: row;
align-items: center;
margin-right: 30upx;
.search-icon {
width: 60upx;
height: 60upx;
}
}
}
}
.tabs-nav-warp{
margin-top: 20upx;
padding:0 30upx;
overflow: hidden;
.tabs-nav{
.ul{
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
.li{
flex: 1 0 auto;
margin-left: 36upx;
font-size: 30upx;
color: #999999;
position: relative;
padding-bottom: 18upx;
text-align: center;
&:first-child{
margin-left: 0;
}
&.on{
&:after{
content: '';
width: 100%;
height: 4upx;
background: #C5AA7B;
position: absolute;
left: 0;
bottom: 0;
}
font-weight:bold;
}
}
}
}
}
</style>

45
components/canvasShow/basics/header/mixin.js

@ -0,0 +1,45 @@
import api from '../../config/api'
import {funMixin} from '../../config/mixin'
export const commonMixin = {
name: 'headerComponent',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
data () {
return {
classifyData: []
}
},
mounted() {
this.getData()
},
methods: {
getData() {
const _ = this
_.sendReq({
url: `${api.getClassify}?page=1&pageSize=20`,
method: 'GET'
}, (res) => {
_.classifyData = res.data
console.log(_.classifyData)
},(err)=>{
})
}
}
}

119
components/canvasShow/basics/imageText.vue

@ -0,0 +1,119 @@
<template>
<div class="imageText warp" :class="['terminal'+terminal,'pos-' + componentContent.positionValue]">
<div class="img img-left">
<a class="item a-link" @click="jumpLink(componentContent.linkObj)"><img :src="componentContent.imageUrl" alt=""></a>
</div>
<div class="text">
<h3 class="h3">{{componentContent.title}}</h3>
<div v-html="componentContent.content"></div>
</div>
<div class="img img-right">
<a class="item a-link" @click="jumpLink(componentContent.linkObj)"><img :src="componentContent.imageUrl" alt=""></a>
</div>
</div>
</template>
<script>
import {funMixin} from '../config/mixin'
export default {
name: 'imageTextComponent',
mixins: [funMixin],
data () {
return {
}
},
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
}
}
</script>
<style lang="scss" scoped>
.imageText{
width: 710upx;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20upx 0;
.img{
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{
width: 100%;
}
.text{
width: 100%;
margin-top: 30upx;
}
.img-right{
display: none;
}
}
&.pos-bottom{
display: block;
text-align: center;
.img{
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>

136
components/canvasShow/basics/imageTextList.vue

@ -0,0 +1,136 @@
<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">
<img ref="getHeight" :src="item.imgData" v-show="item.imgData" :alt="item.title">
</div>
</div>
<div class="text">
<h4 class="h4">{{item.title}}</h4>
<p class="p">{{item.describe}}</p>
</div>
</a>
</div>
</div>
</div>
</template>
<script>
import {funMixin} from '../config/mixin'
export default {
name: 'imageTextList',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
}
}
</script>
<style lang="scss" scoped>
.hom-pro-list{
min-height: 450upx;
padding: 20upx 0;
.title{
margin-bottom: 23upx;
position: relative;
.h2{
font-size: 22upx;
color: #333;
line-height: 1em;
font-weight: bold;
}
}
.ul{
margin: -15upx 0 0 -15upx;
display: flex;
flex-wrap: wrap;
.li{
flex: 0 0 50%;
padding: 15upx 0 0 15upx;
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:16upx 20upx;
text-align: center;
.h4{
line-height: 25upx;
overflow: hidden;
color: #333333;
}
.p{
color: #666666;
padding: 5upx 0 10upx;
}
}
}
}
}
.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

@ -0,0 +1,101 @@
<template>
<div class="ul image-text-nav" :class="'terminal' + terminal">
<div class="li" v-for="(item,index) in componentContent.imgTextData" :key="index" :style="{'flex':'0 0 '+ getItemValue() + '%'}" @click="jumpLink(item.linkObj)">
<!--<router-link class="item" :to="jumpLink(item.linkObj)">-->
<div class="img-box">
<div class="img-box-inner">
<div class="imgBox">
<img class="img" :src="item.img"/>
</div>
</div>
</div>
<h4 class="h4">{{item.title}}</h4>
<!--</router-link>-->
</div>
</div>
</template>
<script>
import {funMixin} from '../config/mixin'
export default {
name: 'imageTextNav',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
},
methods: {
//
getItemValue (val) {
const len = parseInt(this.componentContent.imgTextData.length)
if (len === 0) {
return 0
} else {
return (1 / len * 10000 / 100.00)
}
}
}
}
</script>
<style lang="scss" scoped>
.image-text-nav{
min-height: 100upx;
width: 710upx;
margin: 0 auto;
display: flex;
padding: 20upx 0;
.li{
text-align: center;
.img-box{
.imgBox{
width: 100upx;
height: 100upx;
display: inline-block;
.img{
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
.h4{
font-size: 26upx;
color: #333;
line-height: 33upx;
}
}
&.terminal4{
width: 1000upx;
.li{
.img-box{
display: inline-block;
width: 100upx;
height: 100upx;
box-shadow: 0 10upx 30upx rgba(51, 51, 51, 0.15);
&-inner{
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.imgBox{
width: 60upx;
height: 60upx;
}
}
.h4{
font-size: 18upx;
color: #ccc;
line-height: 1em;
padding-top: 20upx;
}
}
}
}
</style>

71
components/canvasShow/basics/live/app/index.vue

@ -0,0 +1,71 @@
<template>
<div class="live-list-page" v-if="roomList && roomList.length > 0">
<div class="title">
<!-- #ifdef MP-WEIXIN -->
<img class="title-img" src="../../../static/images/live/img-title.png" alt="直播" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="title-img" src="../../../static/images/live/img-title.png" alt="直播" mode="widthFix"/>
<!-- #endif -->
</div>
<div class="live-list">
<LiveBox class="live-item"
v-for="item in roomList"
:key="item.roomid"
:liveData.sync="item"
@click="toLiveRoom(item)"
/>
</div>
<button v-show="componentContent.showMore" class="btn-more" @click="jumpLive()">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
</div>
</template>
<script>
// const NET = require('../../../../../utils/request')
// const API = require('../../../../../config/api')
import {commonMixin} from '../mixin'
import LiveBox from './item.vue'
export default {
mixins: [commonMixin],
components: {
LiveBox
},
}
</script>
<style lang="scss" scoped>
.live-list-page{
.title{
text-align: center;
margin-bottom: 20rpx;
.title-img{
width: 211rpx;
height: 32rpx;
}
}
.live-list{
padding-left: 20rpx;
width: 100%;
display: flex;
flex-wrap: wrap;
.live-item{
margin:0 14rpx 14rpx 0;
width: 348rpx;
height: 464rpx;
border-radius: 8rpx;
overflow: hidden;
}
}
.btn-more {
width: 170rpx;
height: 54rpx;
border: 2rpx solid #C5AA7B;
color: #C5AA7B;
font-size: 24rpx;
background-color: transparent;
margin: 20rpx auto 0;
display: flex;
align-items: center;
}
}
</style>

461
components/canvasShow/basics/live/app/item.vue

@ -0,0 +1,461 @@
<template>
<view class="live-box">
<view class="live-ongoing" v-if="liveData.liveStatus === 101" @click="toLive">
<image class="cover-img" :src="liveData.feedsImg" />
<view class="status">
<view class="status-state">
<!-- #ifdef MP-WEIXIN -->
<img class="img" src="../../../static/images/live/icon-live-num.png" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="img" src="../../../static/images/live/icon-live-num.png" mode="widthFix"/>
<!-- #endif -->
直播中
</view>
<!-- <view class="status-num">1000</view> -->
</view>
<view class="user">
<view class="user-pic">
<image class="img" :src="liveData.anchorHeadImg" />
</view>
<view class="user-name">{{ liveData.anchorNickName }}</view>
</view>
<view class="products">
<view class="uni-padding-wrap">
<view class="page-section swiper">
<view class="page-section-spacing">
<swiper class="swiper"
:indicator-dots="indicatorDots"
:autoplay="autoplay"
:interval="interval"
:duration="duration"
:vertical="true"
>
<swiper-item
v-for="item in liveData.goods"
:key="item.goods_id"
>
<view class="swiper-item">{{ item.name }}</view>
</swiper-item>
</swiper>
</view>
</view>
</view>
</view>
</view>
<view class="live-other" v-else @click="toLive">
<image class="cover-img" :src="liveData.feedsImg" />
<div class="filter-box-warp">
<div class="filter-box">
<image class="cover-img" :src="liveData.feedsImg" />
</div>
</div>
<view class="user">
<view class="user-pic"><image class="img" :src="liveData.anchorHeadImg" /></view>
<view class="user-name">{{ liveData.anchorNickName }}</view>
</view>
<view class="count-down" v-if="liveStatus === 102">
<image v-if="isLate" class="img" src="@/static/images/live/live-late.png"/>
<view class="text">{{ liveTimeTitle }}</view>
<view v-if="!isLate" class="time">
<view class="time-item">{{times[0]}}</view>
<view class="dot">:</view>
<view class="time-item">{{times[1]}}</view>
<view class="dot">:</view>
<view class="time-item">{{times[2]}}</view>
</view>
</view>
<!-- #ifdef MP-WEIXIN -->
<view
v-if="liveStatus === 102 && !isLate"
class="btn-subscribe"
:class="{subscribed : subscribeLive === '已预约'}"
@click.stop="onSubscribe"
>{{ subscribeLive }}</view>
<!-- #endif -->
<view class="endContainer" v-if="liveStatus === 103">
<view class="endBox">
<view></view>
<view></view>
<view></view>
<view></view>
</view>
<view>直播已结束</view>
</view>
</view>
</view>
</template>
<script>
const NET = require('@/utils/request')
const API = require('@/config/api')
import { startLiveTemplate } from '@/config/subscribe.js'
import { liveAppid } from '@/config/live.js'
// #ifdef MP-WEIXIN
const livePlayer = requirePlugin('live-player-plugin')
// #endif
export default {
props: {
liveData: {
type: Object,
default: () => ({
roomId: 0,
anchorNickName: '',
feedsImg: '' //
})
}
},
data () {
return {
background: ['color1', 'color2', 'color3'],
indicatorDots: false,
autoplay: true,
interval: 2000, //
duration: 500, // (ms)
d: 0,
m: 0,
s: 0,
times: [],
liveStatus: 100,
liveTimeTitle: '开播倒计时',
subscribeLive: '立即预约',
timer: null,
isLate: false,
}
},
created() {
this.liveStatus = this.liveData.liveStatus
this.subscribeLive = this.liveData.subscribeStatus === 0 ? '立即预约' : '已预约'
this.getStatus()
this.countTime()
// this.getSubscribeStatus()
},
destroyed() {
clearTimeout(this.timer)
},
methods: {
getStatus() {
if (!this.liveData.roomId) { return }
let _this = this
// #ifdef MP-WEIXIN
livePlayer.getLiveStatus({ room_id: this.liveData.roomId })
.then(res => {
// 101: , 102: , 103: , 104: , 105: , 106: 107
// _this.liveData.liveStatus = res.liveStatus
_this.liveStatus = res.liveStatus
})
.catch(err => {
console.log('get live status', err)
})
this.timer = setInterval(() => {
livePlayer.getLiveStatus({ room_id: this.liveData.roomId })
.then(res => {
// 101: , 102: , 103: , 104: , 105: , 106: 107
_this.liveStatus = res.liveStatus
this.countTime()
console.log('get live status', res.liveStatus)
})
.catch(err => {
console.log('get live status', err)
})
}, 60000)
// #endif
},
changeIndicatorDots(e) {
this.indicatorDots = !this.indicatorDots
},
changeAutoplay(e) {
this.autoplay = !this.autoplay
},
intervalChange(e) {
this.interval = e.target.value
},
durationChange(e) {
this.duration = e.target.value
},
countTime(){
var nowtime = new Date().getTime() //
const starttime = new Date(this.liveData.startTime).getTime()
if(this.liveStatus === 102){
if(starttime > nowtime){
var lefttime = starttime - nowtime //
var leftd = Math.floor(lefttime/(1000*60*60)), //
leftm = Math.floor(lefttime/(1000*60)%60), //
lefts = Math.floor(lefttime/1000%60); //
this.times = [leftd < 10?'0'+ leftd:leftd,leftm < 10?'0'+ leftm:leftm,lefts < 10?'0'+ lefts:lefts]
this.liveTimeTitle = '开播倒计时'
setTimeout(() => {
this.countTime()
},1000)
} else {
this.times = ['00', '00', '00']
this.isLate = true
this.liveTimeTitle = '正在赶来的路上...'
}
}
},
toLive() {
console.log(liveAppid,'liveAppid')
console.log(this.liveData.roomId,'this.liveData.roomId')
if (!liveAppid || !this.liveData) { return }
//
// let customParams = encodeURIComponent(JSON.stringify({ path: 'livePage/index', pid: 1 }))
// #ifdef MP-WEIXIN
wx.navigateTo({
url: `plugin-private://${liveAppid}/pages/live-player-plugin?room_id=${this.liveData.roomId}`
// url: `plugin-private://${liveAppid}/pages/live-player-plugin?room_id=${this.liveData.roomId}&custom_params=${customParams}`
})
// #endif
},
onSubscribe() {
if (this.subscribeLive === '立即预约') {
const _this = this
// #ifdef MP-WEIXIN
uni.requestSubscribeMessage({
tmplIds: [startLiveTemplate],
success (res) {
if (res[startLiveTemplate] === "accept") {
NET.request(API.SubScribeLive, {id: _this.liveData.id }, 'post')
.then(res => {
if (res.data) {
_this.subscribeLive = '已预约'
} else {
uni.showToast({
title: res.message || '订阅失败,请稍后再试!',
icon: "none"
})
}
})
.catch(err => {
console.log(err)
uni.showToast({
title: res.message || '订阅失败,请稍后再试!',
icon: "none"
})
})
}
}
})
// #endif
}
}
}
}
</script>
<style lang="scss" scoped>
.live-box{
position: relative;
color: #fff;
width: 100%;
height: 100%;
.cover-img{
width: 100%;
height: 100%;
position: absolute;
z-index: 0;
}
.user{
display: flex;
line-height: 60rpx;
height: 64rpx;
&-pic{
.img{
width: 60rpx;
height: 60rpx;
border: 2px solid rgba(255, 255, 255, 0.5019607843137255);
border-radius: 50%;
overflow: hidden;
}
}
&-name{
font-size: 28rpx;
margin-left: 16rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 245rpx;
}
}
.live-ongoing{
width: 100%;
height: 100%;
position: relative;
.status{
position: absolute;
top: 22rpx;
left: 22rpx;
//width: 212upx;
height: 48rpx;
// background: rgba(0,0,0,0.3);
// border: 2rpx solid rgba(255,255,255,0.3);
border-radius: 24rpx;
font-size: 20rpx;
line-height: 44rpx;
display: flex;
// padding-right: 8rpx;
&-state{
width: 118rpx;
height: 44rpx;
background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
opacity: 1;
border-radius: 26rpx;
display: flex;
align-items: center;
justify-content: center;
.img{
width: 20rpx;
height: 20rpx;
margin-right: 6rpx;
}
}
&-num{
min-width: 80rpx;
padding: 0 8rpx;
}
}
.user{
position: absolute;
bottom: 62rpx;
left: 20rpx;
}
.products{
position: absolute;
left: 0rpx;
bottom: 20rpx;
width: 100%;
padding:0 20rpx;
.swiper{
height: 34rpx;
line-height: 34rpx;
font-size: 24rpx;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
}
}
.live-other{
position: relative;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.filter-box-warp{
background-color: #000000;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
.filter-box{
position: absolute;
top: -30rpx;
left: -30rpx;
width: 348rpx;
height: 464rpx;
display: flex;
align-items: center;
justify-content: center;
-webkit-filter: blur(20px);
-moz-filter: blur(21px);
-ms-filter: blur(20px);
-o-filter: blur(20px);
padding: 30rpx;
box-sizing: content-box;
}
}
.user{
position: absolute;
top: 20rpx;
left: 20rpx;
}
.count-down{
position: relative;
.text{
font-size: 26rpx;
line-height: 36rpx;
margin-bottom: 16rpx;
opacity: 0.5;
text-align: center;
}
.img{
display: block;
width: 80rpx;
height: 80rpx;
margin: 16rpx auto;
}
.time{
display: flex;
justify-content: space-around;
align-items: center;
&-item{
min-width: 52rpx;
padding: 0 5rpx;
height: 52rpx;
line-height: 52rpx;
background: #FFFFFF;
opacity: 1;
border-radius: 6rpx;
font-size: 26rpx;
color: #C83732;
text-align: center;
.dot{
line-height: 52rpx;
}
}
}
}
.btn-subscribe{
width: 200rpx;
height: 64rpx;
line-height: 64rpx;
background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
box-shadow: 0rpx 6rpx 12rpx rgba(233, 0, 0, 0.3);
opacity: 1;
border-radius: 6rpx;
color: #fff;
font-size: 24rpx;
text-align: center;
position: absolute;
bottom: 60rpx;
left: 50%;
margin-left: -100rpx;
&.subscribed{
background: #FFFFFF;
color: #999999;
box-shadow: none;
}
}
.endContainer{
position: relative;
.endBox{
width: 40%;
height: 60rpx;
margin: 20rpx auto;
display: flex;
justify-content: space-between;
align-items: flex-end;
view{
width: 0;
border: 2rpx solid #FFF;
}
view:nth-of-type(1){
height: 20%;
}
view:nth-of-type(2){
height: 50%;
}
view:nth-of-type(3){
height: 30%;
}
view:nth-of-type(4){
height: 70%;
}
}
}
}
}
</style>

60
components/canvasShow/basics/live/mixin.js

@ -0,0 +1,60 @@
const NET = require('@/utils/request')
const API = require('@/config/api')
import {funMixin} from '../../config/mixin'
export const commonMixin = {
mixins: [funMixin],
data() {
return {
appid: 'wx2b03c6e691cd7370',
roomId: [], // 填写具体的房间号
roomList: [],
page: {
page: 1,
pageSize: 6,
},
}
},
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
created() {
this.getLiveRooms()
},
methods: {
// 获取直播间列表
getLiveRooms () {
NET.request(API.LiveRoomes, this.page, 'get').then(res => {
console.log(res)
this.roomList = res.data.list
})
},
toLiveRoom (item) {
this.roomId.push(item.roomid)
if (!this.appid || !this.roomId.length) { return }
// 路由参数
let customParams = encodeURIComponent(JSON.stringify({ path: 'livePage/index', pid: 1 }))
// let customParams
// 开发者在直播间页面路径上携带自定义参数(如示例中的path和pid参数),后续可以在分享卡片链接和跳转至商详页时获取,详见【获取自定义参数】、【直播间到商详页面携带参数】章节(上限600个字符,超过部分会被截断)
// #ifdef MP-WEIXIN
wx.navigateTo({
url: `plugin-private://${this.appid}/pages/live-player-plugin?room_id=${this.roomId}&custom_params=${customParams}`
})
// #endif
}
}
}

196
components/canvasShow/basics/newProduct/app/index.vue

@ -0,0 +1,196 @@
<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">
<img 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 -->
<img class="iconImg" v-if="item.activityType == 1" src="../../../static/images/groupBuyIcon.png">
<img class="iconImg" v-if="item.activityType == 2" src="../../../static/images/spikeIcon.png">
<img class="iconImg" v-if="item.activityType == 4" src="../../../static/images/spikeIcon.png">
<img class="iconImg" v-if="item.activityType == 3" src="../../../static/images/discountListIcon.png">
<img class="iconImg" v-if="item.activityType == 5" src="../../../static/images/discountListIcon.png">
<img class="iconImg" v-if="item.activityType == 9" src="../../../static/images/memberCenterIcon.png">
<img 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="../../../static/images/groupBuyIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 2" src="../../../static/images/spikeIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 4" src="../../../static/images/spikeIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 3" src="../../../static/images/discountListIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 5" src="../../../static/images/discountListIcon.png"></image>
<image class="iconImg" v-if="item.activityType == 9" src="../../../static/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>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
// data () {
// return {
// index: 1,
// swiperOption: {
// slidesPerView: 3,
// spaceBetween: 12,
// autoplay: false, //
// loop: true,
// pagination: {
// el: '.new-pagination'
// }
// }
// }
// }
}
</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("../../../static/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("../../../static/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>

89
components/canvasShow/basics/newProduct/mixin.js

@ -0,0 +1,89 @@
import {funMixin} from '../../config/mixin'
// import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
// import 'swiper/css/swiper.css'
import api from '../../config/api'
export const commonMixin = {
name: 'productList',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
// components: {
// Swiper,
// SwiperSlide
// },
// directives: {
// swiper: directive
// },
data () {
return {
productData: []
}
},
mounted() {
this.getData(true)
},
watch: {
'componentContent': {
handler(newVal, oldVal) {
this.getData()
},
deep: true
}
},
methods: {
getData(isFirst) {
const _ = this
if (_.componentContent.productData.sourceType === '1') {
if(_.componentContent.productData.productIdList && _.componentContent.productData.productIdList.length>0){
_.sendReq({
url: `${api.getProducts}?page=1&pageSize=99&ids=${_.componentContent.productData.productIdList}`,
method: 'GET'
}, (proRes) => {
_.productData = proRes.data.list
if(isFirst){
_.componentContent.productData.imgTextData = _.productData
}
// _.$forceUpdate() // 刷新轮播图
})
} else {
_.productData = []
}
} else if(_.componentContent.productData.sourceType === '2'){
if(_.componentContent.productData.categoryId) {
_.sendReq({
url: `${api.getProducts}?page=1&pageSize=99&classifyId=${_.componentContent.productData.categoryId}`,
method: 'GET'
}, (proRes) => {
_.productData = proRes.data.list
if(isFirst){
_.componentContent.productData.imgTextData = _.productData
}
_.$forceUpdate() // 刷新轮播图
// _.swiper.update()
})
} else {
_.productData = []
}
}
}
},
}

96
components/canvasShow/basics/notice.vue

@ -0,0 +1,96 @@
<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>
import api from '../config/api'
import { funMixin } from '../config/mixin'
import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'
export default {
name: "noticeComponent",
mixins: [funMixin],
data () {
return {
noticesList: [],
}
},
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
},
mounted() {
this.getData()
},
methods: {
getData() {
const _ = this
let _url = `${api.getNotices}`
const params = {
method: 'GET',
url: _url,
}
this.sendReq(params, (res) => {
_.noticesList = res.data
})
}
}
}
</script>
<style lang="scss" scoped>
.notice-list{
height: 60upx;
line-height: 60upx;
overflow: hidden;
.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;
background: url("../static/images/notice/ico_notice2.png") no-repeat left center;
background-size: 30upx 30upx;
}
}
&.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;
background: url("../static/images/notice/ico_notice.png") no-repeat left center;
}
}
}
}
</style>

218
components/canvasShow/basics/price/app/index.vue

@ -0,0 +1,218 @@
<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 -->
<img class="title-img" src="../../../static/images/price/img-title.png" alt="组合优惠" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="title-img" src="../../../static/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">
<img 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>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperCurrent: 0,
}
},
methods:{
swiperChange(e) {
this.swiperCurrent = 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>

73
components/canvasShow/basics/price/mixin.js

@ -0,0 +1,73 @@
import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'
import api from '../../config/api'
import {funMixin} from '../../config/mixin'
export const commonMixin = {
name: 'price',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
components: {
Swiper,
SwiperSlide
},
directives: {
swiper: directive
},
data () {
return {
productData: {
composeProducts: [],
rules: []
}
}
},
watch: {
'componentContent': {
handler(newVal, oldVal) {
this.getData()
},
deep: true
}
},
created() {
this.getData()
},
methods: {
getData() {
const _ = this
if(_.componentContent.priceId){
const params = {
method: 'GET',
url: `${api.getPrices}?shopId=${_.shopId}&ids=${_.componentContent.priceId}&page=1&pageSize=10`,
}
this.sendReq(params, (res) => {
if( res.data.length > 0){
_.productData = res.data[0]
}
})
} else {
_.productData = {
composeProducts: [],
rules: []
}
}
},
}
}

253
components/canvasShow/basics/price/pc/index.vue

@ -0,0 +1,253 @@
<template>
<div class="product-list" :class="'terminal'+terminal">
<div class="picListWarp" v-if="componentContent.arrangeType == '横向滑动'">
<div class="picList" v-if="productData.products && productData.products.length>0">
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<swiper class="products-swiper" :options="swiperOption">
<swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData.composeProducts" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<div class="discount-text">
<span>任选{{productData.rules[0].number}}{{productData.rules[0].price}}</span>
</div>
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<span>¥{{item.price}}</span>
</div>
<button class="btn-cart" @click="addCart(item.id)">加入购物车</button>
</div>
</div>
</swiper-slide>
</swiper>
</div>
</div>
<div v-else class="picList" >
<ul class="clearfix" :class="'imgTextNum' + componentContent.productNum">
<li class="item" v-for="(item,index) in productData.composeProducts.slice(0, componentContent.productRowNum * componentContent.productNum)" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<div class="discount-text">
<span>任选{{productData.rules[0].number}}{{productData.rules[0].price}}</span>
</div>
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<span>¥{{item.price}}</span>
</div>
<button class="btn-cart" @click="addCart(item.id)">加入购物车</button>
</div>
</div>
</li>
</ul>
</div>
<button v-show="componentContent.showMore" class="btn-more" @click="jumpPice(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperOption: {
slidesPerView: 4, //
spaceBetween: 13, //
autoplay: false, //
loop: true,
pagination: {
el: '.price-pagination'
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
}
}
}
}
</script>
<style lang="scss" scoped>
.product-list{
padding: 20px 0;
background-color: #fff;
.picListWarp{
width: 1380px;
max-width: 100%;
margin: 0 auto;
position: relative;
}
.picList{
width: 1200px;
max-width: 100%;
margin: 0 auto;
.swiper-button-prev,.swiper-button-next{
width: 50px;
height: 50px;
position: absolute;
cursor:pointer;
top: 140px;
background-repeat: no-repeat;
&:after{
content: '';
}
}
.swiper-button-prev{
left: 0;
background: url('../../../static/images/btn-prev.png');
}
.swiper-button-next{
right: 0;
background: url('../../../static/images/btn-next.png');
}
.a-link{
cursor: pointer;
&:hover{
box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
}
.itemImgBox {
height: auto;
display: flex;
flex-direction: column;
justify-content: center;
.imgBox {
padding-bottom: 100%;
background-color: #cacaca;
position: relative;
.el-image {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
}
}
.text{
padding:25px 10px 17px;
text-align: center;
position: relative;
//height: 180px;
.discount-text{
background: url("../../../static/images/price/bg-discount.png") no-repeat;
width: 100%;
height: 47px;
font-size: 14px;
color: #fff;
line-height: 60px;
text-align: center;
position: absolute;
top: -47px;
left: 0;
}
.h4{
font-size: 18px;
line-height: 24px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
color: #333333;
//max-height: 48px;
}
.p{
color: #999;
font-size: 16px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
padding-top: 18px;
position: relative;
margin-top: 8px;
&:after{
position: absolute;
top: 0;
left: 50%;
margin-left: -80px;
width: 160px;
height: 2px;
background: #F0F0F0;
content: '';
}
}
.priceBox {
padding-top: 11px;
line-height: 33px;
span {
font-size: 25px;
color: #C83732;
padding-right: 12px;
}
span.discount {
font-size: 18px;
color: #ccc;
text-decoration: line-through;
}
}
.btn-cart{
margin-top: 5px;
width: 270px;
height: 40px;
background-color: #333;
font-size: 18px;
color: #FFEBC4;
}
}
}
ul{
margin: -15px 0 0 -15px;
display: flex;
flex-wrap: wrap;
li{
flex: 0 0 50%;
padding: 15px 0 0 15px;
width: 0;
}
}
.imgTextNum2 {
li {
flex: 0 0 50%;
}
}
.imgTextNum3 {
li {
flex: 0 0 33.33%;
}
}
.imgTextNum4 {
li {
flex: 0 0 25%;
}
}
.imgTextNum5 {
li {
flex: 0 0 20%;
}
}
}
}
.btn-more {
width: 130px;
height: 41px;
border: 2px solid #C5AA7B;
color: #C5AA7B;
font-size: 18px;
background-color: transparent;
margin: 20px auto 0;
display: block;
}
</style>

564
components/canvasShow/basics/product/app/index.vue

@ -0,0 +1,564 @@
<template>
<div class="hom-pro-list">
<div class="title">
<!-- #ifdef MP-WEIXIN -->
<img
class="title-img"
src="../../../static/images/product/img-title.png"
alt="商品推荐"
mode="widthFix"
/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image
class="title-img"
src="../../../static/images/product/img-title.png"
alt="商品推荐"
mode="widthFix"
/>
<!-- #endif -->
</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" v-if="JSON.stringify(item)!=='{}'" @click="jumpProductDetail(item)">
<div class="product-list-img">
<img
class="img pic-img default-img"
:src="item.image"
>
</div>
<div class="product-list-info">
<label class="product-name">{{ item.productName }}</label>
<div class="flex">
<div
class="shop-box"
v-if="typeId == 1"
@click.stop="jumpStore(item)"
>
<label class="shop-name">{{ item.shopName }}</label>
<div class="shop-logo">
<img :src="item.shopLogo">
</div>
</div>
<label class="buy-count">已售{{ item.number ? item.number : 0 }}</label>
</div>
<div class="price-warp">
<!-- #ifdef MP-WEIXIN -->
<img
class="iconImg"
v-if="item.activityType == 1"
src="../../../static/images/groupBuyIcon.png"
>
<img
class="iconImg"
v-if="item.activityType == 2"
src="../../../static/images/spikeIcon.png"
>
<img
class="iconImg"
v-if="item.activityType == 4"
src="../../../static/images/spikeIcon.png"
>
<img
class="iconImg"
v-if="item.activityType == 3"
src="../../../static/images/discountListIcon.png"
>
<img
class="iconImg"
v-if="item.activityType == 5"
src="../../../static/images/discountListIcon.png"
>
<img
class="iconImg"
v-if="item.activityType == 9"
src="../../../static/images/memberCenterIcon.png"
>
<img
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="../../../static/images/groupBuyIcon.png"
>
<image
class="iconImg"
v-if="item.activityType == 2"
src="../../../static/images/spikeIcon.png"
>
<image
class="iconImg"
v-if="item.activityType == 4"
src="../../../static/images/spikeIcon.png"
>
<image
class="iconImg"
v-if="item.activityType == 3"
src="../../../static/images/discountListIcon.png"
>
<image
class="iconImg"
v-if="item.activityType == 5"
src="../../../static/images/discountListIcon.png"
>
<image
class="iconImg"
v-if="item.activityType == 9"
src="../../../static/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 -->
<div class="price">
¥ {{ item.price }}
</div>
<div class="original-price">
¥ {{ item.originalPrice }}
</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">
<div
class="product-list-item-warp"
v-for="(item,index) in productData"
:key="index"
>
<div
@click="jumpProductDetail(item)"
class="product-list-item"
v-if="JSON.stringify(item)!=='{}'"
>
<div class="product-list-img">
<img
class="img pic-img default-img"
:src="item.image"
>
</div>
<div class="product-list-info">
<label class="product-name">{{ item.productName }}</label>
<div class="flex">
<div
class="shop-box"
v-if="typeId == 1"
@click.stop="jumpStore(item)"
>
<label class="shop-name">{{ item.shopName }}</label>
<div class="shop-logo">
<img :src="item.shopLogo">
</div>
</div>
<label class="buy-count">已售{{ item.number ? item.number : 0 }}</label>
</div>
<div class="price-warp">
<!-- #ifdef MP-WEIXIN -->
<img
class="iconImg"
v-if="item.activityType == 1"
src="../../../static/images/groupBuyIcon.png"
/>
<img
class="iconImg"
v-if="item.activityType == 2"
src="../../../static/images/spikeIcon.png"
/>
<img
class="iconImg"
v-if="item.activityType == 4"
src="../../../static/images/spikeIcon.png"
/>
<img
class="iconImg"
v-if="item.activityType == 3"
src="../../../static/images/discountListIcon.png"
/>
<img
class="iconImg"
v-if="item.activityType == 5"
src="../../../static/images/discountListIcon.png"
/>
<img
class="iconImg"
v-if="item.activityType == 9"
src="../../../static/images/memberCenterIcon.png"
/>
<img
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="../../../static/images/groupBuyIcon.png"
/>
<image
class="iconImg"
v-if="item.activityType == 2"
src="../../../static/images/spikeIcon.png"
/>
<image
class="iconImg"
v-if="item.activityType == 4"
src="../../../static/images/spikeIcon.png"
/>
<image
class="iconImg"
v-if="item.activityType == 3"
src="../../../static/images/discountListIcon.png"
/>
<image
class="iconImg"
v-if="item.activityType == 5"
src="../../../static/images/discountListIcon.png"
/>
<image
class="iconImg"
v-if="item.activityType == 9"
src="../../../static/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 -->
<div class="price">
¥ {{ item.price }}
</div>
<div class="original-price">
¥ {{ item.originalPrice }}
</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>
</div>
</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>
import { commonMixin } from '../mixin'
export default {
mixins: [commonMixin],
data() {
return {
swiperCurrent: 0,
}
},
methods: {
swiperChange(e) {
this.swiperCurrent = e.detail.current;
}
}
}
</script>
<style
lang="scss"
scoped
>
.hom-pro-list {
padding: 20rpx 13rpx;
.title {
text-align: center;
margin-bottom: 20rpx;
.title-img {
width: 211rpx;
}
}
/**多行多列**/
.product-list {
position: relative;
&-box {
display: flex;
flex-wrap: wrap;
flex-direction: row;
&.swiper {
height: 620rpx;
}
}
&.product-swiper .product-list-box {
padding-left: 0;
}
&-item-warp {
margin: 0 0 20rpx 0;
}
&-item {
width: 348rpx;
padding: 0 7rpx;
box-sizing: content-box;
}
&-img {
width: 348rpx;
height: 348rpx;
background-color: #f5f5f5;
border-radius: 10rpx 10rpx 0 0;
.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: 18rpx;
line-height: 40rpx;
}
.flex {
display: flex;
align-items: center;
}
.shop-box {
background-color: #333333;
border-radius: 0rpx 20rpx 20rpx 0rpx;
line-height: 40rpx;
display: flex;
align-items: center;
height: 40rpx;
margin-right: 10rpx;
.shop-name {
font-size: 20rpx;
color: #FFEBC4;
padding: 0 8rpx 0 12rpx;
}
.shop-logo {
border: 2rpx solid #707070;
border-radius: 50%;
overflow: hidden;
float: right;
img {
width: 34rpx;
height: 34rpx;
display: block;
}
}
}
.buy-count {
color: #C5AA7B;
font-size: 20rpx;
border: 2rpx solid #E4E5E6;
line-height: 40rpx;
padding: 0 5rpx;
}
.price-warp {
display: flex;
align-items: baseline;
line-height: 56rpx;
.iconImg {
width: 58rpx;
height: 36rpx;
margin-right: 10rpx;
}
.price {
color: #C83732;
font-size: 40rpx;
margin-right: 20rpx;
}
.original-price {
font-size: 24rpx;
color: #ccc;
text-decoration: line-through;
}
}
}
//::v-deep .swiper-pagination-bullet{
// display: none;
//}
}
}
//::v-deep .uni-swiper-dots{
// display: flex;
// justify-content: center;
// padding: 10rpx 0;
// .uni-swiper-dot{
// width: 10rpx;
// height: 10rpx;
// background: #333333;
// opacity: 0.3;
// border-radius: 5rpx;
// margin: 0 5rpx;
// &-active{
// width: 20rpx;
// height: 10rpx;
// opacity: 1;
// }
// }
//}
.swiper-dots {
display: flex;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 15rpx;
z-index: 66;
.dot {
width: 10rpx;
height: 10rpx;
background: #333333;
opacity: 0.3;
border-radius: 5rpx;
margin: 0 10rpx;
}
.dot-active {
width: 20rpx;
opacity: 1;
}
}
//.pagination{
// display: flex;
// justify-content: center;
// padding: 20rpx 0;
// ::v-deep .swiper-pagination-bullet{
// width: 10rpx;
// height: 10rpx;
// background: #333333;
// opacity: 0.3;
// border-radius: 5rpx;
// margin: 0 5rpx;
// }
// ::v-deep .swiper-pagination-bullet-active{
// width: 20rpx;
// height: 10rpx;
// 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;
}
</style>

96
components/canvasShow/basics/product/mixin.js

@ -0,0 +1,96 @@
// import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
// import 'swiper/css/swiper.css'
import {funMixin} from '../../config/mixin'
import api from '../../config/api'
export const commonMixin = {
name: 'productList',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
// components: {
// Swiper,
// SwiperSlide
// },
// directives: {
// swiper: directive
// },
data () {
return {
productData: []
}
},
watch: {
'componentContent': {
handler(newVal, oldVal) {
this.getData()
},
deep: true
}
},
created() {
this.getData(true)
},
computed: {
swiper() {
if(this.$refs.mySwiper){
return this.$refs.mySwiper.$swiper
}
}
},
methods: {
getData(isFirst) {
const _ = this
this.productData = [{},{},{},{},{},{},{},{}]
if (_.componentContent.productData.sourceType === '1') {
if(_.componentContent.productData.productIdList && _.componentContent.productData.productIdList.length>0){
_.sendReq({
url: `${api.getProducts}?page=1&pageSize=99&ids=${_.componentContent.productData.productIdList}`,
method: 'GET'
}, (proRes) => {
_.productData = proRes.data.list
_.productData = _.productData.filter(item=>JSON.stringify(item) !== '{}')
if(isFirst){
_.componentContent.productData.imgTextData = _.productData
}
})
} else {
_.productData = []
}
} else if(_.componentContent.productData.sourceType === '2'){
if(_.componentContent.productData.categoryId) {
_.sendReq({
url: `${api.getProducts}?page=1&pageSize=99&classifyId=${_.componentContent.productData.categoryId}`,
method: 'GET'
}, (proRes) => {
_.productData = proRes.data.list
_.productData = _.productData.filter(item=>JSON.stringify(item) !== '{}')
if(isFirst){
_.componentContent.productData.imgTextData = _.productData
}
// _.swiper.update()
})
} else {
_.productData = {
products:[]
}
}
}
},
}
}

226
components/canvasShow/basics/product/pc/index.vue

@ -0,0 +1,226 @@
<template>
<div class="product-list" :class="'terminal'+terminal">
<div class="picListWarp" v-if="componentContent.arrangeType == '横向滑动'">
<div class="picList" v-if="productData && productData.length>0">
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<swiper ref="swiper" class="products-swiper" :options="swiperOption">
<swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<span>¥{{item.price}}</span>
<span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
</div>
</div>
</div>
</swiper-slide>
</swiper>
</div>
</div>
<div v-else class="picList" >
<ul class="clearfix" :class="'imgTextNum' + componentContent.productNum">
<li class="item" v-for="(item,index) in productData.slice(0, componentContent.productRowNum * componentContent.productNum)" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<span>¥{{item.price}}</span>
<span class="discount" v-if="item.originalPrice">¥{{item.originalPrice}}</span>
</div>
</div>
</div>
</li>
</ul>
</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>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperOption: {
slidesPerView: 4, //
spaceBetween: 13, //
autoplay: false, //
loop: true,
pagination: {
el: '.product-pagination'
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
}
}
}
}
</script>
<style lang="scss" scoped>
.product-list{
padding: 20px 0;
background-color: #fff;
.picListWarp{
width: 1380px;
max-width: 100%;
margin: 0 auto;
position: relative;
}
.picList{
width: 1200px;
max-width: 100%;
margin: 0 auto;
.swiper-button-prev,.swiper-button-next{
width: 50px;
height: 50px;
position: absolute;
cursor:pointer;
top: 140px;
background-repeat: no-repeat;
&:after{
content: '';
}
}
.swiper-button-prev{
left: 0;
background: url('../../../static/images/btn-prev.png');
}
.swiper-button-next{
right: 0;
background: url('../../../static/images/btn-next.png');
}
.a-link{
cursor: pointer;
&:hover{
box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
}
.itemImgBox {
height: auto;
display: flex;
flex-direction: column;
justify-content: center;
.imgBox {
padding-bottom: 100%;
background-color: #cacaca;
position: relative;
.el-image {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
}
}
.text{
padding:25px 20px 17px;
text-align: center;
//height: 180px;
.h4{
font-size: 18px;
line-height: 24px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
color: #333333;
//max-height: 48px;
}
.p{
color: #999;
font-size: 16px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
padding-top: 18px;
position: relative;
margin-top: 8px;
&:after{
position: absolute;
top: 0;
left: 50%;
margin-left: -80px;
width: 160px;
height: 2px;
background: #F0F0F0;
content: '';
}
}
.priceBox {
padding-top: 11px;
line-height: 33px;
span {
font-size: 25px;
color: #C83732;
padding-right: 12px;
}
span.discount {
font-size: 18px;
color: #ccc;
text-decoration: line-through;
}
}
}
}
ul{
margin: -15px 0 0 -15px;
display: flex;
flex-wrap: wrap;
li{
flex: 0 0 50%;
padding: 15px 0 0 15px;
width: 0;
}
}
.imgTextNum2 {
li {
flex: 0 0 50%;
}
}
.imgTextNum3 {
li {
flex: 0 0 33.33%;
}
}
.imgTextNum4 {
li {
flex: 0 0 25%;
}
}
.imgTextNum5 {
li {
flex: 0 0 20%;
}
}
}
}
.btn-more {
width: 130px;
height: 41px;
border: 2px solid #C5AA7B;
color: #C5AA7B;
font-size: 18px;
background-color: transparent;
margin: 20px auto 0;
display: block;
}
</style>

157
components/canvasShow/basics/shop.vue

@ -0,0 +1,157 @@
<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">
<img 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>
// import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
// import 'swiper/css/swiper.css'
import {funMixin} from '../config/mixin'
export default {
name: 'shop',
mixins: [funMixin],
data () {
return {
swiperCurrent: 0,
}
},
methods:{
swiperChange(e) {
this.swiperCurrent = e.detail.current;
}
},
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
},
// components: {
// Swiper,
// SwiperSlide
// },
// directives: {
// swiper: directive
// },
computed: {
imgList: function () {
console.log(this.componentContent)
return this.componentContent.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>

168
components/canvasShow/basics/spike/app/index.vue

@ -0,0 +1,168 @@
<template>
<div class="spike">
<div class="spike-card" v-if="productData.products && productData.products.length>0">
<div class="spike-card-top">
<h2 class="spike-card-top-title">
<!-- #ifdef MP-WEIXIN -->
<img class="title-img" src="../../../static/images/spike/img-title.png" alt="秒杀专区" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="title-img" src="../../../static/images/spike/img-title.png" alt="秒杀专区" mode="widthFix"/>
<!-- #endif -->
</h2>
<div class="spike-card-top-time" v-if="state===2">
活动已结束
</div>
<div class="spike-card-top-time" v-if="state !==2 && count.length">
距离{{count[0]}}还有 <div class="span">{{count[1]}}:{{count[2]}}:{{count[3]}}</div>
</div>
<a class="btn-more" @click="jumpSeckills(productData)">更多<i class="iconfont icon-arrow-right"></i></a>
</div>
<div class="spike-card-list">
<div class="spike-card-item" v-for='item in productData.products.slice(0,4)' :key='item.productId' @click="jumpProductDetail(item)">
<div class="spike-card-item-img">
<img :src="item.image" alt="">
</div>
<div class="spike-card-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>
</div>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin]
}
</script>
<style lang="scss" scoped>
.spike{
background: #F8F8F8;
padding: 20upx;
&-card{
height: 430upx;
background: #FFFFFF;
border-radius: 20upx;
&-top{
position: relative;
padding: 32upx 0 22upx;
display: flex;
&-title{
padding: 9upx 20upx 9upx 30upx;
.title-img{
width: 204upx;
display: block;
}
}
&-time{
padding: 0 18upx;
height: 50upx;
background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
box-shadow: 0px 6upx 12upx rgba(233, 0, 0, 0.3);
opacity: 1;
border-radius: 26upx;
font-size: 24upx;
line-height: 50upx;
color: #fff;
text-align: center;
.span{
display: inline;
}
}
.btn-more{
position: absolute;
right: 8upx;
top: 40upx;
line-height: 33upx;
padding-right: 25upx;
font-size: 24upx;
color: #333;
.iconfont{
content: '';
font-size: 26upx;
position: absolute;
right: 0;
top: 0;
}
}
}
&-list{}
&-item{
width: 50%;
border-top: 1px solid #F3F4F5;
border-left: 1px solid #F3F4F5;
float: left;
align-items: center;
box-sizing: border-box;
&:nth-child(2n+1){
border-left: 0px;
}
&-img{
width: 162upx;
height: 162upx;
margin-right: 10upx;
float: left;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
&-info{
height: 100%;
margin-left: 172upx;
width: 168upx;
.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;
}
}
}
}
}
</style>

137
components/canvasShow/basics/spike/mixin.js

@ -0,0 +1,137 @@
import api from '../../config/api'
import {funMixin} from '../../config/mixin'
export const commonMixin = {
name: 'spikeList',
mixins: [funMixin],
data () {
return {
productData: {
products: []
},
count: [],
state: 0,
timer: null
}
},
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
watch: {
'componentContent': {
handler(newVal, oldVal) {
this.getData()
},
deep: true
}
},
created() {
this.getData()
},
methods: {
getData() {
const _ = this
if(_.componentContent.shopSeckillId){
if(this.typeId === 1){
const params = {
method: 'GET',
url: `${api.getPlatformSeckills}?ids=${_.componentContent.shopSeckillId}`,
}
this.sendReq(params, (res) => {
if(res.data.length> 0){
_.productData = res.data[0]
_.productData.products.map(function(value){
value.sliderVal = (value.stockNumber/value.total*100).toFixed(2)
return value;
});
// 只有进行中和未开始活动, 用倒计时
this.timer = setInterval(()=>{
_.getTime(_.productData)
}, 1000)
}
})
}
if(this.typeId === 3){
const params = {
method: 'GET',
url: `${api.getSeckills}?shopId=${_.shopId}&ids=${_.componentContent.shopSeckillId}`,
}
this.sendReq(params, (res) => {
if(res.data.length> 0){
_.productData = res.data[0]
_.productData.products.map(function(value){
value.sliderVal = (value.stockNumber/value.total*100).toFixed(2)
return value;
});
// 只有进行中和未开始活动, 用倒计时
if(_.productData.state !==2) {
this.timer = setInterval(()=>{
_.getTime(_.productData)
}, 1000)
}
} else {
_.productData = {
products:[]
}
}
})
}
} else {
_.productData = {
products:[]
}
}
},
getTime(info) {
const date = new Date().getTime()
let startTime = ''
let endTime = ''
if(this.typeId === 1){
startTime = new Date(info.startTime.replace(/-/g,'/')).getTime()
endTime = new Date(info.endTime.replace(/-/g,'/')).getTime()
} else {
startTime = new Date(info.effectiveStart.replace(/-/g,'/')).getTime()
endTime = new Date(info.effectiveEnd.replace(/-/g,'/')).getTime()
}
if(date > endTime){
this.state = 2
} else if(startTime > date) {
this.state = 0
this.countDown(startTime-date) // 未开始
} else {
this.state = 1
this.countDown(endTime-date) // 进行中
}
},
countDown(time) {
const fn = (v) => v < 10 ? `0${v}` : v
const t = parseInt(time / 1000)
const text = this.state == 0 ? '开始' : '结束'
const hour = parseInt(t / 3600)
const min = parseInt((t % 3600) / 60)
const s = t % 60
// console.log(min, '分',t)
this.count = [text, fn(hour), fn(min), fn(s)]
// console.log(text, fn(hour), fn(min), fn(s))
}
},
beforeDestroy() {
clearInterval(this.timer)
}
}

211
components/canvasShow/basics/spike/pc/index.vue

@ -0,0 +1,211 @@
<template>
<div class="spikeList" :class="'terminal'+terminal">
<div class="warp" v-if="componentContent.shopSeckillId && productData">
<div>
<div class="spikeCard">
<div class="listLeft">
<img src="../../../static/images/spike/bg-spike.png">
<div class="bgBox">
<div class="title"><img src="../../../static/images/spike/tit-spike.png" alt="秒杀专区"></div>
<div class="text">整点秒杀数量有限</div>
<div class="sessions">{{productData.seckillName}} {{isStart && '倒计时'}}</div>
<div class="time-text">距离{{count[0]}}还有</div>
<div class="timeBox">
<span>{{count[1]}}</span><i>:</i><span>{{count[2]}}</span><i>:</i><span>{{count[3]}}</span>
</div>
<button class="btn-more" @click="jumpSeckills(productData)">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
</div>
</div>
<div class="listRight">
<div class="listItem" v-for='it in productData.products' :key='it.productId' @click="jumpProductDetail(it)">
<div class="imgBox">
<img :src="it.image" alt="">
</div>
<div class="itemInfo">
<h3>{{it.productName}}</h3>
<div class="begrenzt">
<span class="people">还剩{{it.stockNumber}}</span>
<div class="progress" :style="{'width':it.sliderVal + '%'}"></div>
</div>
<div class="originalPrice">¥{{it.originalPrice}}</div>
<dl class="discountPrice">
<dt>
<img src="../../../static/images/spike/flag-spike.png" alt="秒杀价">
</dt>
<dd>
<span></span><b>{{it.price}}</b>
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin]
}
</script>
<style lang="scss" scoped>
.spikeList{
min-height: 100px;
&.terminal4{
background-color: #F3F4F5;
.warp{
width: 1200px;
}
.spikeCard {
display: flex;
width: 100%;
.listLeft {
width: 487px;
height: 758px;
text-align: center;
position: relative;
.bgBox {
position: absolute;
top: 0;
left: 0;
width: 100%;
.title{
padding-top: 140px;
}
.text{
color: #8E8D8C;
font-size: 30px;
line-height: 40px;
margin: 15px 0 100px 0;
}
.sessions{
color: #FFEBC4;
font-size: 30px;
line-height: 40px;
}
.time-text{
padding-top: 60px;
color: #FFEBC4;
font-size: 18px;
}
.timeBox {
display: flex;
align-items: center;
justify-content: center;
margin:10px 0 50px;
span {
display: block;
width: 60px;
height: 60px;
background: rgba(51,51,51,0.8);
color: #FFFFFF;
font-size: 30px;
line-height: 60px;
}
i {
font-size: 30px;
color: #fff;
font-style: normal;
font-weight: bold;
padding: 0 13px;
}
}
.btn-more {
width: 130px;
height: 41px;
border: 2px solid #FFEBC4;
color: #FFEBC4;
font-size: 18px;
background-color: transparent;
}
}
}
.listRight {
padding: 40px 0 0 8px;
.listItem {
float:left;
width: 220px;
height: 335px;
margin:0 0 15px 15px;
background-color: #fff;
.imgBox {
width: 220px;
height: 220px;
img {
width: 100%;
height: 100%;
}
}
.itemInfo {
position: relative;
padding: 10px;
text-align: center;
h3{
font-size: 14px;
color: #333;
line-height: 18px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
.begrenzt{
position: absolute;
left: 5px;
top: -35px;
width: 210px;
height: 30px;
border: 1px solid #C83732;
background-color: #C83732;
text-align: center;
.people{
position: relative;
z-index: 2;
font-size: 12px;
color: #FFBAB8;
line-height: 30px;
}
.progress{
position: absolute;
right: 0;
top: 0;
background-color: #fff;
height: 28px;
}
}
.discountPrice {
display: inline-block;
width: 130px;
dt{
float: left;
}
dd{
border: 1px solid #F3F4F5;
color: #C83732;
line-height: 30px;
font-weight: bold;
span {
font-size: 18px;
}
b {
font-size: 18px;
}
}
}
.originalPrice {
font-size: 14px;
line-height: 19px;
padding: 10px 0 6px;
color: #ccc;
text-decoration: line-through;
}
}
}
}
}
}
}
</style>

79
components/canvasShow/basics/text.vue

@ -0,0 +1,79 @@
<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+'px',fontWeight:componentContent.textFontW,color:componentContent.titColor}">{{componentContent.title}}</h3>
<p class="p" :style="{fontSize:componentContent.describeSizeNum+'px',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>
export default {
name: 'textComponent',
data () {
return {
}
},
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
}
}
</script>
<style lang="scss" scoped>
.text{
padding: 0 20upx;
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>

120
components/canvasShow/basics/video.vue

@ -0,0 +1,120 @@
<template>
<div class="videoBox warp" :class="'terminal' + terminal">
<div class="videoLeftBox">
<h3>{{componentContent.title}}</h3>
<div v-html="componentContent.mainBody"></div>
</div>
<div class="videoRightBox" v-if="componentContent.coverImg && isPlay">
<video class="myVideo" id="myVideo" :src="componentContent.videoUrl" enable-danmu danmu-btn controls></video>
</div>
<div class="videoCoverBox" v-if="componentContent.coverImg && !isPlay" @click="handlePlayVideo">
<image :src="componentContent.coverImg" ></image>
</div>
<div class="videoRightBox" v-if="!componentContent.coverImg">
<video class="myVideo" id="myVideo" :src="componentContent.videoUrl" enable-danmu danmu-btn controls></video>
</div>
<div class="clear"></div>
</div>
</template>
<script>
export default {
name: 'videoBox',
props: {
terminal: {
type: Number,
default: 4
},
componentContent: {
type: Object
}
},
created(){
console.log('componentContent',this.componentContent)
},
mounted() {
this.videoContext = uni.createVideoContext('myVideo',this)
},
data () {
return {
isPlay:false,
videoContext:null
}
},
methods:{
handlePlayVideo(){
this.isPlay = true
setTimeout(()=>{
this.videoContext.play()
},500)
}
}
}
</script>
<style lang="scss" scoped>
.videoBox {
padding: 20upx 0;
display: flex;
justify-content: flex-start;
align-items: center;
.videoLeftBox {
width: 50%;
padding-right: 10%;
h3 {
font-size: 28upx;
color: #333333;
margin-bottom: 30upx;
}
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;
margin-bottom: 20upx;
}
.videoRightBox {
width: 100%;
}
}
}
.videoCoverBox{
aspect-ratio: 16/9;
position: relative;
&:before{
content: '';
width: 0rpx;
height: 0rpx;
border-left:80rpx solid #fff;
border-right:50rpx solid transparent;
border-top:50rpx solid transparent;
border-bottom:50rpx solid transparent;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-30%,-50%);
z-index: 99;
}
image{
width: 100%;
height: 100%;
}
}
</style>

319
components/canvasShow/basics/vip/app/index.vue

@ -0,0 +1,319 @@
<template>
<div class="vip">
<div class="vip-card">
<div class="vip-title">
<!-- #ifdef MP-WEIXIN -->
<img class="title-img" src="../../../static/images/vip/img-title.png" alt="会员专区" mode="widthFix"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="title-img" src="../../../static/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 -->
<img src="../../../static/images/vip/flag-vip.png" alt="会员价" class="flagImg"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="flagImg" src="../../../static/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>
<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">
<img 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 -->
<img src="../../../static/images/vip/flag-vip.png" alt="会员价" class="flagImg"/>
<!-- #endif -->
<!-- #ifdef H5 || APP-PLUS -->
<image class="flagImg" src="../../../static/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>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperCurrent: 0,
}
},
computed: {
listTemp: function () {
var list = this.productData;
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;
}
},
methods:{
swiperChange(e) {
this.swiperCurrent = e.detail.current;
}
}
}
</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>

60
components/canvasShow/basics/vip/mixin.js

@ -0,0 +1,60 @@
// import { directive, Swiper, SwiperSlide } from 'vue-awesome-swiper'
// import 'swiper/css/swiper.css'
import api from '../../config/api'
import {funMixin} from '../../config/mixin'
export const commonMixin = {
name: 'productList',
mixins: [funMixin],
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentContent: {
type: Object
}
},
// components: {
// Swiper,
// SwiperSlide
// },
// directives: {
// swiper: directive
// },
data () {
return {
productData: []
}
},
watch: {
'componentContent': {
handler(newVal, oldVal) {
this.getData()
},
deep: true
}
},
created() {
this.getData()
},
methods: {
getData() {
const _ = this
_.sendReq({
url: `${api.getMemberProducts}?page=1&pageSize=20`,
method: 'GET'
}, (proRes) => {
_.productData = proRes.data.list
})
}
}
}

241
components/canvasShow/basics/vip/pc/index.vue

@ -0,0 +1,241 @@
<template>
<div class="product-list" :class="'terminal'+terminal">
<div class="picListWarp" v-if="componentContent.arrangeType == '横向滑动'">
<div class="picList" v-if="productData && productData.length>0">
<div class="vip-button-prev"></div>
<div class="vip-button-next"></div>
<swiper class="products-swiper" :options="swiperOption">
<swiper-slide class="products-swiper-slide item" v-for="(item,index) in productData" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<dl>
<dt><img src="../../../static/images/vip/flag-vip.png" alt="会员价"></dt>
<dd>
¥{{item.price}}
</dd>
</dl>
</div>
</div>
</div>
</swiper-slide>
</swiper>
</div>
</div>
<div v-else class="picList" >
<ul class="clearfix" :class="'imgTextNum' + componentContent.productNum">
<li class="item" v-for="(item,index) in productData.slice(0, componentContent.productRowNum * componentContent.productNum)" :key="index">
<div class="a-link" @click="jumpProductDetail(item)">
<div class="itemImgBox">
<div class="imgBox">
<el-image
:src="item.image"
fit="contain"></el-image>
</div>
</div>
<div class="text">
<h4 class="h4">{{item.productName}}</h4>
<div class="priceBox">
<dl>
<dt><img src="../../../static/images/vip/flag-vip.png" alt="会员价"></dt>
<dd>
¥{{item.price}}
</dd>
</dl>
</div>
</div>
</div>
</li>
</ul>
</div>
<button v-show="componentContent.showMore" class="btn-more" @click="jumpVip">查看全部 <span class="icon iconfont icon-arrow-right"></span></button>
</div>
</template>
<script>
import {commonMixin} from '../mixin'
export default {
mixins: [commonMixin],
data () {
return {
swiperOption: {
slidesPerView: 4, //
spaceBetween: 13, //
autoplay: false, //
loop: true,
pagination: {
el: '.vip-pagination'
},
navigation: {
nextEl: '.vip-button-next',
prevEl: '.vip-button-prev'
}
}
}
}
}
</script>
<style lang="scss" scoped>
.product-list{
padding: 20px 0;
background-color: #fff;
.picListWarp{
width: 1380px;
max-width: 100%;
margin: 0 auto;
position: relative;
}
.picList{
width: 1200px;
max-width: 100%;
margin: 0 auto;
.vip-button-prev,.vip-button-next{
width: 50px;
height: 50px;
position: absolute;
cursor:pointer;
top: 140px;
background-repeat: no-repeat;
&:after{
content: '';
}
}
.vip-button-prev{
left: 0;
background: url('../../../static/images/btn-prev.png');
}
.vip-button-next{
right: 0;
background: url('../../../static/images/btn-next.png');
}
.a-link{
cursor: pointer;
&:hover{
box-shadow: 3px 4px 20px 0px rgba(186, 186, 186, 0.5);
}
.itemImgBox {
height: auto;
display: flex;
flex-direction: column;
justify-content: center;
.imgBox {
padding-bottom: 100%;
background-color: #cacaca;
position: relative;
.el-image {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
}
}
.text{
padding:25px 20px 17px;
text-align: center;
//height: 180px;
.h4{
font-size: 18px;
line-height: 24px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
color: #333333;
margin-bottom: 15px;
//max-height: 48px;
}
.p{
color: #999;
font-size: 16px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
padding-top: 18px;
position: relative;
margin-top: 8px;
&:after{
position: absolute;
top: 0;
left: 50%;
margin-left: -80px;
width: 160px;
height: 2px;
background: #F0F0F0;
content: '';
}
}
.priceBox {
dl {
display: inline-block;
min-width: 130px;
dt{
float: left;
img{
display: block;
}
}
dd{
border: 1px solid #F3F4F5;
font-size: 25px;
line-height: 34px;
color: #C83732;
margin-left: 57px;
padding: 0 10px;
}
}
}
}
}
ul{
margin: -15px 0 0 -15px;
display: flex;
flex-wrap: wrap;
li{
flex: 0 0 50%;
padding: 15px 0 0 15px;
width: 0;
}
}
.imgTextNum2 {
li {
flex: 0 0 50%;
}
}
.imgTextNum3 {
li {
flex: 0 0 33.33%;
}
}
.imgTextNum4 {
li {
flex: 0 0 25%;
}
}
.imgTextNum5 {
li {
flex: 0 0 20%;
}
}
}
}
.btn-more {
width: 130px;
height: 41px;
border: 2px solid #C5AA7B;
color: #C5AA7B;
font-size: 18px;
background-color: transparent;
margin: 20px auto 0;
display: block;
}
</style>

226
components/canvasShow/canvasShowPage.vue

@ -0,0 +1,226 @@
<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-banner v-if="item.type==='banner'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-banner>
<com-text v-if="item.type==='text'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-text>
<com-image-text v-if="item.type==='imageText'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-image-text>
<com-brand-list v-if="item.type==='brandList'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-brand-list>
<com-category-list v-if="item.type==='categoryList'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-category-list>
<com-image-text-list v-if="item.type==='imageTextList'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-image-text-list>
<com-assist-div v-if="item.type==='assistDiv'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-assist-div>
<com-image-text-nav v-if="item.type==='imageTextNav'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-image-text-nav>
<com-product v-if="item.type==='productList'"
ref="productPage"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-product>
<com-video-box v-if="item.type==='videoBox'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-video-box>
<com-coupon v-if="item.type==='coupon'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-coupon>
<com-custom v-if="item.type==='custom'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-custom>
<com-notice v-if="item.type==='notice'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-notice>
<com-vip v-if="item.type==='vip'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-vip>
<com-group v-if="item.type==='groupList'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-group>
<com-discount v-if="item.type==='discountList'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-discount>
<com-spike v-if="item.type==='spikeList'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-spike>
<com-price v-if="item.type==='priceList'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-price>
<com-new-product v-if="item.type==='newProduct'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-new-product>
<com-shop v-if="item.type==='shop'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-shop>
<com-live v-if="item.type==='live'"
:componentContent="item.componentContent"
:terminal="terminal"
:typeId="typeId"
:shopId="shopId"></com-live>
</div>
</div>
</template>
<script>
// import comComponentMap from './componentMap'
import comBanner from '@/components/canvasShow/basics/banner'
import comText from '@/components/canvasShow/basics/text'
import comImageText from '@/components/canvasShow/basics/imageText'
import comBrandList from '@/components/canvasShow/basics/brandList'
import comCategoryList from '@/components/canvasShow/basics/categoryList'
import comImageTextList from '@/components/canvasShow/basics/imageTextList'
import comAssistDiv from '@/components/canvasShow/basics/assistDiv'
import comImageTextNav from '@/components/canvasShow/basics/imageTextNav'
import comProduct from '@/components/canvasShow/basics/product/app/index'
import comVideoBox from '@/components/canvasShow/basics/video'
import comCoupon from '@/components/canvasShow/basics/coupon/app'
import comCustom from '@/components/canvasShow/basics/custom'
import comNotice from '@/components/canvasShow/basics/notice'
import comVip from '@/components/canvasShow/basics/vip/app'
import comGroup from '@/components/canvasShow/basics/group/app/index'
import comDiscount from '@/components/canvasShow/basics/discount/app'
import comSpike from '@/components/canvasShow/basics/spike/app'
import comPrice from '@/components/canvasShow/basics/price/app'
import comNewProduct from '@/components/canvasShow/basics/newProduct/app'
import comShop from '@/components/canvasShow/basics/shop'
import comLive from '@/components/canvasShow/basics/live/app'
import {sendReqMixin} from './config/mixin'
export default {
name: 'canvasPage',
mixins: [sendReqMixin],
data() {
return {
// terminal: 4, // 1 2 H53 App 4
// typeId: 3, // 1 2 3
// shopId: 0, // id
// componentsData: [],
// componentMap: componentMap
}
},
components: {
comBanner,
comText,
comImageText,
comBrandList,
comCategoryList,
comImageTextList,
comAssistDiv,
comImageTextNav,
comProduct,
comVideoBox,
comCoupon,
comCustom,
comGroup,
comDiscount,
comSpike,
comPrice,
comNotice,
comVip,
comNewProduct,
comShop,
comLive
},
props: {
terminal: {
type: Number,
default: 4
},
typeId: {
type: Number,
default: 1
},
shopId: {
type: Number,
default: 0
},
componentsData: {
type: Array,
default: ()=>[]
}
},
methods: {
}
}
</script>
<style lang="scss"
scoped>
.hom-layout {
background-color: #ffffff;
width: 100%;
overflow: hidden;
}
</style>
<style lang="scss">
.warp {
width: 710upx;
margin: 0 auto;
max-width: 100%;
&.terminal4 {
width: 1200px;
max-width: 100%;
}
}
.flex-box {
display: flex;
}
</style>

32
components/canvasShow/config/api.js

@ -0,0 +1,32 @@
// 导入api接口模块
// 获取当前环境变量 true => 生产环境 false => 开发环境
// const BASEURL = process.env.VUE_APP_DOMAIN_PREFIX
const BASEURL = (process.env.NODE_ENV === 'production') ? 'https://ceres.zkthink.com/api' : 'https://ceres.zkthink.com/api'
// const BASEURL = (process.env.NODE_ENV === 'production') ? 'http://127.0.0.1:9007' : 'http://127.0.0.1:9007'
export const api = {
// 画布模块
fileUpload: BASEURL + '/file/upload', // 文件上传
getClassify: BASEURL + '/canvas/getClassify', // 查询分类层级
getProducts: BASEURL + '/canvas/getProducts', // 选择商品查询
saveCanvas: BASEURL + '/canvas/saveCanvas', // 保存画布
getCanvas: BASEURL + '/canvas/getCanvas', // 读取画布
getShops: BASEURL + '/canvas/getShops', // 选择店铺查询
getCoupons: BASEURL + '/canvas/getCoupons', // 优惠券查询
getShopCoupons: BASEURL + '/canvas/getShopCoupons', // 优惠券查询
takeCoupon: BASEURL + '/coupon/takeCoupon', // 领取优惠券
selectCanvasCustomList: BASEURL + '/canvas/selectCanvasCustomList', // 自定义页面查询
getPlatformSeckills: `${BASEURL}/canvas/getPlatformSeckills`, // 平台秒杀活动
getSeckills: `${BASEURL}/renovation/getSeckills`, // 商家秒杀活动
getMinDiscount: `${BASEURL}/canvas/getMinDiscount`, // 平台限时折扣
getDiscounts: `${BASEURL}/renovation/getDiscounts`, // 商家限时折扣
getAdminGroupWorks: `${BASEURL}/canvas/getGroupWorks`, // 平台拼团专区
getGroupWorks: `${BASEURL}/renovation/getGroupWorks`, // 商家拼团专区
getPriceProducts: `${BASEURL}/canvas/getPriceProducts`, // 商家定价捆绑
getPrices: `${BASEURL}/canvas/getPrices`, // 商家定价捆绑
getMemberProducts: `${BASEURL}/canvas/getMemberProducts`, // 查询会员商品数据
getNotices: `${BASEURL}/canvas/getNotices`, // 平台获取公告数据
}
export default api

12
components/canvasShow/config/config.js

@ -0,0 +1,12 @@
// 画布配置
// 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
}
}
export default config

204
components/canvasShow/config/mixin/funMixin.js

@ -0,0 +1,204 @@
// import router from '@/router'
import api from '../api'
import {sendReq} from './sendReqMixin'
import { mapMutations } from 'vuex'
import canvasConfig from '../config'
/*
* 公共方法的 mixin
*/
export const tool = {
mixins: [sendReq],
props: {
isNoData: {
type: Boolean,
default: false
},
comType: {
type: String,
default: ''
}
},
mounted() {
// console.log('加载了组件')
},
methods: {
...mapMutations({
setCurrentPro: 'SET_CURRENTPRO'
}),
// 判断url
jumpLink (linkObj) {
var link = ''
console.log(linkObj.data)
if(linkObj && linkObj.typeText && linkObj.data){
switch (linkObj.typeText) {
case '类别':
this.jumpCategory(linkObj.data)
break
case '店辅':
this.jumpStore(linkObj.data)
break
case '商品':
this.jumpProductDetail(linkObj.data)
break
case '自定义':
// router.push("/category");
case '公告':
this.jumpNoticeDetail(linkObj.data)
break
}
} else if(linkObj.selsectValue==='/index'){
uni.navigateTo({
url: `/pages/index/index`
})
}
return link
},
// 跳转到类别主页
jumpCategory(item){
uni.navigateTo({
url: `/pages_category_page1/goodsModule/goodsList?category3Id=${item.id}`
})
},
// 跳转到产品列表
jumpProList(item){
if(item.sourceType === '1'){
uni.navigateTo({
url: `/pages_category_page1/goodsModule/canvasGoods?sourceType=${item.sourceType}&ids=${item.productIdList}`
})
} else if(item.sourceType === '2'){
uni.navigateTo({
url: `/pages_category_page1/goodsModule/canvasGoods?sourceType=${item.sourceType}&classifyId=${item.categoryId}`
})
}
},
// 跳转到店铺主页
jumpStore(item){
uni.navigateTo({
url: `/pages_category_page1/store/index?storeId=${item.shopId}`
})
},
// 跳转到商品详情
jumpProductDetail(item){
uni.navigateTo({
url: '/pages_category_page1/goodsModule/goodsDetails?shopId=' + item.shopId + '&productId=' + item.productId + '&skuId=' + item
.skuId
})
},
// 跳转到秒杀专区
jumpSeckills(item){
if(item.shopId){
uni.navigateTo({
url: '/pages_category_page1/discount/spikeList?shopId=' + item.shopId + '&shopSeckillId=' + item.shopSeckillId
})
} else {
uni.navigateTo({
url: '/pages_category_page1/discount/spikeList'
})
}
},
// 跳转到拼团专区
jumpGroupWorks(item){
if(item.shopId){
uni.navigateTo({
url: '/pages_category_page1/discount/groupBuy?shopId=' + item.shopId + '&shopGroupWorkId=' + item.shopGroupWorkId
})
} else {
uni.navigateTo({
url: '/pages_category_page1/discount/groupBuy?'
})
}
},
// 跳转到折扣专区
jumpDiscount(item){
if(item.shopId){
if (item.shopDiscountId) {
uni.navigateTo({
url: '/pages_category_page1/discount/discount?shopId=' + item.shopId + '&shopDiscountId=' + item.shopDiscountId
})
} else {
uni.showToast({
title: '暂无活动',
icon: "none"
});
}
} else {
if (item.discountId) {
uni.navigateTo({
url: '/pages_category_page1/discount/platformDiscount?discountId=' + item.discountId
})
} else {
uni.showToast({
title: '暂无活动',
icon: "none"
});
}
}
},
// 跳转到会员专区
jumpVip(){
uni.navigateTo({
url: '/pages_category_page1/memberCenter/activityList',
success: res => {},fail: () => {},complete: () => {}
})
},
// 跳转组合支付
jumpCombination(item){
if (item.priceId) {
uni.navigateTo({
url: '/pages_category_page1/goodsModule/combination?priceId=' + item.priceId
})
} else {
uni.showToast({
title: '暂无活动',
icon: "none"
});
}
},
// 跳转到公告详情
jumpNoticeDetail(item){
uni.navigateTo({
url: '/pages_category_page2/userModule/messageDetail?noticeId=' + item.noticeId
})
},
// 跳转到直播列表
jumpLive(){
uni.navigateTo({
url: '/pages_category_page2/livePage/index'
})
},
// 领取优惠券
// receiveCoupon(item) {
// var key = canvasConfig.getToken()
// if (key) {
// var paramsData = {}
// if(this.typeId === 1){
// paramsData.couponId = item.couponId
// } else if(this.typeId === 3) {
// paramsData.shopCouponId = item.shopCouponId
// paramsData.shopId = this.shopId
// }
// let params = {
// url: api.takeCoupon,
// method: 'POST',
// data: paramsData
// }
// this.sendReq(params, (res) => {
// this.$message({
// message: '领取成功!',
// type: 'success'
// })
// this.getData()
// })
// } else {
// this.$message({
// message: '请先登录'
// })
// this.$router.push({path: '/login'})
// }
// },
// 加入购物车
addCart(id){
console.log(id)
}
}
}

9
components/canvasShow/config/mixin/index.js

@ -0,0 +1,9 @@
/*
* 用于组件复用
* 参考链接 https://cn.vuejs.org/v2/guide/mixins.html#全局混合
* 混合 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式混合对象可以包含任意组件选项以组件使用混合对象时所有混合对象的选项将被混入该组件本身的选项
*/
import { tool } from './funMixin.js'
import { sendReq } from './sendReqMixin.js'
export const funMixin = { ...tool }
export const sendReqMixin = { ...sendReq }

37
components/canvasShow/config/mixin/sendReqMixin.js

@ -0,0 +1,37 @@
/*
* 发送请求 mixin
*/
import request from './server'
/* eslint-disable */
export const sendReq = {
data () {
return {
// 加载中
loading: false,
}
},
methods: {
/*
* 发送请求
*/
sendReq (params, callback) {
let self = this
request({
method: params.method || 'POST',
url: params.url,
data: params.data || {},
withCredentials : true,
headers: {
'Content-type': params.contentType || 'application/json;charset=utf-8'
}
}).then((res) => {
if (res && res.data) {
callback && callback(res.data)
}
}, (error) => {
console.log(error)
})
}
}
}

135
components/canvasShow/config/mixin/server.js

@ -0,0 +1,135 @@
// 引入axios
// import router from './../../router'
import Vue from 'vue'
// import promise from 'es6-promise'
import axios from 'axios'
import canvasConfig from '../config'
// 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)
}
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)
// 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 service

BIN
components/canvasShow/static/images/btn-next.png

After

Width: 50  |  Height: 50  |  Size: 849 B

BIN
components/canvasShow/static/images/btn-next2.png

After

Width: 95  |  Height: 95  |  Size: 4.6 KiB

BIN
components/canvasShow/static/images/btn-prev.png

After

Width: 50  |  Height: 50  |  Size: 861 B

BIN
components/canvasShow/static/images/btn-prev2.png

After

Width: 95  |  Height: 95  |  Size: 4.6 KiB

BIN
components/canvasShow/static/images/coupon/bg-coupon.png

After

Width: 335  |  Height: 292  |  Size: 8.2 KiB

BIN
components/canvasShow/static/images/coupon/bg-coupon2.png

After

Width: 335  |  Height: 292  |  Size: 7.2 KiB

BIN
components/canvasShow/static/images/coupon/border_L1.png

After

Width: 20  |  Height: 122  |  Size: 1.3 KiB

0
components/canvasShow/static/images/coupon/border_L2.png

0
components/canvasShow/static/images/coupon/border_L3.png

0
components/canvasShow/static/images/coupon/border_L4.png

0
components/canvasShow/static/images/coupon/border_R1.png

0
components/canvasShow/static/images/coupon/border_R2.png

0
components/canvasShow/static/images/coupon/border_R3.png

0
components/canvasShow/static/images/coupon/border_R4.png

BIN
components/canvasShow/static/images/coupon/flag-coupon-r.png

After

Width: 71  |  Height: 71  |  Size: 2.3 KiB

BIN
components/canvasShow/static/images/coupon/flag-coupon.png

After

Width: 71  |  Height: 71  |  Size: 2.7 KiB

BIN
components/canvasShow/static/images/coupon/flag-coupon2-r.png

After

Width: 71  |  Height: 71  |  Size: 2.2 KiB

BIN
components/canvasShow/static/images/coupon/flag-coupon2.png

After

Width: 71  |  Height: 71  |  Size: 2.6 KiB

BIN
components/canvasShow/static/images/discount/bg-discount-top-text.png

After

Width: 176  |  Height: 83  |  Size: 4.1 KiB

BIN
components/canvasShow/static/images/discount/bg-discount-top.png

After

Width: 1200  |  Height: 250  |  Size: 46 KiB

BIN
components/canvasShow/static/images/discount/flag-discount.png

After

Width: 57  |  Height: 36  |  Size: 1.9 KiB

BIN
components/canvasShow/static/images/discount/flag-discount2.png

After

Width: 100  |  Height: 40  |  Size: 3.2 KiB

BIN
components/canvasShow/static/images/discount/img-title.png

After

Width: 203  |  Height: 32  |  Size: 7.4 KiB

BIN
components/canvasShow/static/images/discountListIcon.png

After

Width: 58  |  Height: 36  |  Size: 1.4 KiB

BIN
components/canvasShow/static/images/group/flag-group.png

After

Width: 57  |  Height: 36  |  Size: 2.0 KiB

BIN
components/canvasShow/static/images/group/img-title.png

After

Width: 189  |  Height: 33  |  Size: 6.2 KiB

BIN
components/canvasShow/static/images/groupBuyIcon.png

After

Width: 58  |  Height: 36  |  Size: 1.5 KiB

BIN
components/canvasShow/static/images/icon-title.png

After

Width: 36  |  Height: 32  |  Size: 720 B

BIN
components/canvasShow/static/images/live/huabei.png

After

Width: 446  |  Height: 446  |  Size: 9.1 KiB

BIN
components/canvasShow/static/images/live/icon-live-num.png

After

Width: 20  |  Height: 20  |  Size: 381 B

BIN
components/canvasShow/static/images/live/img-title.png

After

Width: 211  |  Height: 32  |  Size: 4.7 KiB

BIN
components/canvasShow/static/images/memberCenterIcon.png

After

Width: 58  |  Height: 36  |  Size: 1.3 KiB

BIN
components/canvasShow/static/images/newProduct/bg-product-card.png

After

Width: 710  |  Height: 454  |  Size: 20 KiB

BIN
components/canvasShow/static/images/newProduct/flag-new.png

After

Width: 54  |  Height: 54  |  Size: 1.3 KiB

BIN
components/canvasShow/static/images/notice/ico_notice.png

After

Width: 15  |  Height: 16  |  Size: 737 B

BIN
components/canvasShow/static/images/notice/ico_notice2.png

After

Width: 30  |  Height: 31  |  Size: 1.2 KiB

BIN
components/canvasShow/static/images/price/bg-discount.png

After

Width: 290  |  Height: 47  |  Size: 9.7 KiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save