Commit 39f5d340 by 程南

提交新增功能

parent a3325348
......@@ -115,6 +115,14 @@
"pages/belongWithGuide/belongWithGuide"
]
},
{
"root": "omniChannel/",
"pages": [
"pages/productDetail/productDetail"
]
},
{
"root": "subPackageMarketing/page",
"pages": [
......
......@@ -6,7 +6,7 @@
// 修改 BRANCH_ID 为对应的商户id
// app.js 中brandId 修改为对应
const PROJECT_ENV = 'test' // 生产 prod, 开发 dev, 测试 test , 测试门户 test_store, 预生产 pre
const PROJECT_ENV = 'prod' // 生产 prod, 开发 dev, 测试 test , 测试门户 test_store, 预生产 pre
//仅生产环境时 配置 :
//3001 3001 , wx313ec36b710125d4 有直播
//2006 泰华 , wx40fec8944623c8b3 有直播
......@@ -25,7 +25,7 @@ const PROJECT_ENV = 'test' // 生产 prod, 开发 dev, 测试 test , 测试门
//2992 山东盛联微商城 wx53dedc202ae0d0c2
//2002 巴黎贝甜 wx21968cb3a486d4ab
const BRANCH_ID = 1002
const BRANCH_ID = 2010
const isMall = true
// const needMock = '' //
......
const wxService = require('../../../utils/wxService')
Component({
/**
* 组件的属性列表
*/
properties: {
isFirst: Boolean
},
/**
* 组件的初始数据
*/
data: {},
methods: {
closeTips() {
wxService.nextTick(() => {
this.triggerEvent('closeTips')
})
}
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--component/addTips/addTips.wxml -->
<view wx:if="{{isFirst}}">
<view class="triangle" />
<view class='add-tip'>
<view>点击“·<span style="vertical-align:middle">•</span>·”添加到我的小程序,
<span class="closeTips" bindtap="closeTips"></span>
</view>
<view>微信首页下拉即可快速访问店铺</view>
</view>
</view>
.add-tip {
position: fixed;
top: 25rpx;
right: 2%;
background: #FFF;
border-radius: 10rpx;
z-index: 499;
height: 120rpx;
width: 58%;
line-height: 40rpx;
padding: 20rpx 20rpx;
box-sizing: border-box;
overflow: hidden;
box-shadow:0 0 10px rgba(0, 52, 52, .5);
font-size: 0rpx;
}
.closeTips {
margin-top: -4px;
position: absolute;
right: 36rpx;
display: inline-block;
width: 24rpx;
height: 24rpx;
overflow: hidden;
border: 1px solid;
color:#ccc;
border-radius: 50%;
}
.closeTips::before, .closeTips::after {
content: '';
position: absolute;
height: 2rpx;
width: 70%;
top: 50%;
left: 4rpx;
background: #ccc;
}
.closeTips::before {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
.closeTips::after {
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
.triangle {
position: fixed;
top: -13rpx;
right: 18%;
width: 0px;
height: 0px;
z-index: 500;
font-size: 0;
line-height: 0;
overflow: hidden;
border-width: 10px;
border-style: dashed dashed solid dashed;
border-color: transparent transparent #fff transparent;
}
// components/footerTip.js
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/footerTip.wxml-->
<view class='footer-tip'>
<text>提示:满减/满折等,订单提交页核算并扣减金额</text>
</view>
/* components/footerTip.wxss */
.footer-tip {
position: fixed;
left: 0;
bottom: 90rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
width: 100%;
color: #ec6655;
background: #fff
}
.footer-tip text {
font-size: 20rpx;
}
\ No newline at end of file
// components/goods/goodsItem.js
Component({
/**
* 组件的属性列表
*/
properties: {
goodsInfo: {
type: Object,
value: {},
observer: '_updateGoodsInfo'
},
imageSize: {
type: String,
value: 'small'
},
imageSouceName: {
type: String,
value: 'list_urls'
}
},
/**
* 组件的初始数据
*/
data: {
goodsImagePath: ''
},
/**
* 组件的方法列表
*/
methods: {
_update (newV, oldV) {
if (newV !== oldV) {
this.setData({
goodsInfo: newV
})
}
},
_setGoodsImagePath () {
let imageUrls = this.data.goodsInfo.goodsImages
let urlName = this.data.imageSouceName
let size = this.data.imageSize
var url = ''
if (imageUrls && imageUrls !== 'null') {
var imagesObj = JSON.parse(imageUrls)
var urls = imagesObj[urlName]
var len = urls.length
switch (size) {
case 'big':
url = urls[len - 1]
break
case 'normal':
url = urls[1]
break
case 'small':
url = urls[0]
break
}
}
return url
}
},
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function () {
const imagePath = this._setGoodsImagePath()
this.setData({
goodsImagePath: imagePath
})
},
moved: function () { },
detached: function () { }
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/goods/goodsItem.wxml-->
<wxs src="../../wxs/utils.wxs" module="tools" />
<view class='goods-detail'>
<view class='goods-box'>
<block>
<image src='{{tools.getImageUrl(goodsInfo.listImgUrlList,imageSize)}}' class='goods-image'></image>
</block>
<view class='goods-content'>
<view class='goods-name'>{{goodsInfo.name}}</view>
<view class='goods-bottom'>
<view class='goods-code'>{{goodsInfo.girard}}</view>
<view class='goods-color'>{{goodsInfo.colorName}}</view>
<view class='goods-size'>{{goodsInfo.sizeName}}</view>
</view>
</view>
<view class='goods-num'>×{{goodsInfo.count}}</view>
<view class='goods-price'>¥{{goodsInfo.price}}</view>
</view>
</view>
/* components/goods/goodsItem.wxss */
.goods-title {
padding-left: 13rpx;
color: #2f2f2f;
font-size: 30rpx;
margin-bottom: 31rpx;
}
.goods-box {
padding: 14rpx 36rpx 15rpx 14rpx;
margin-bottom: 7rpx;
display: flex;
align-items: center;
background-color: #f8f8f8;
}
.goods-content {
flex: 3;
}
.goods-image {
width: 71rpx;
height: 71rpx;
margin-right: 25rpx;
}
.goods-name {
font-size: 30rpx;
color: #2f2f2f;
}
.goods-bottom {
/* margin-top: 9rpx; */
font-size: 25rpx;
color: #959595;
display: flex;
}
.goods-code, .goods-size, .goods-color {
flex: 1;
text-align: center;
}
.goods-price {
text-align: right;
}
.goods-num {
flex: 1;
font-size: 24rpx;
color: #959595;
text-align: center;
/* padding-top: 25rpx; */
}
.goods-price {
/* padding-top: 19rpx; */
font-size: 33rpx;
color: #d10d16;
font-weight: bold;
}
// component/html2wxml/wxHtml.js
const wxParser = require('../../../wxParser/index')
Component({
/**
* 组件的属性列表
*/
properties: {
config: {
type: Object,
observer: '_configChange',
value: null
},
html: {
type: String,
value: '',
observer: '_htmlChange'
}
},
/**
* 组件的初始数据
*/
data: {
},
created () {
this.init()
},
attached: function () {
},
moved: function () { },
detached: function () {
this._htmlChange = null
this._configChange = null
},
/**
* 组件的方法列表
*/
methods: {
init: function (config) {
config = config || {
bind: 'richText',
html: this.data.html || ``,
target: this,
enablePreviewImage: false, // 禁用图片预览功能
tapLink: (url) => { // 点击超链接时的回调函数
// url 就是 HTML 富文本中 a 标签的 href 属性值
// 这里可以自定义点击事件逻辑,比如页面跳转
wx.navigateTo({
url
})
}
}
this.data.config = config
},
_parse: function (config) {
wxParser.parse(config)
},
_parseHtml (html) {
let config = this.data.config
config.html = html
this._parse(config)
},
_configChange (newV, oldV) {
if (newV !== oldV) {
this._parse(newV)
}
},
_htmlChange (newV, oldV) {
if (newV !== oldV) {
this._parseHtml(newV)
}
}
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--component/html2wxml/wxHtml.wxml-->
<view class='wx-html'>
<import src="../wxParser/index.wxml"/>
<view class="wxParser">
<template is="wxParser" data="{{wxParserData:richText.nodes}}"/>
</view>
</view>
/* component/html2wxml/wxHtml.wxss */
@import '../../wxParser/index.wxss'
\ No newline at end of file
// component/productGuarantee/productGuarantee.js
Component({
/**
* 组件的属性列表
*/
properties: {
show: { // 显示标识
type: Boolean,
value: false
},
normalShow: { // 普通商详服务条款显示标识
type: Boolean,
value: false
},
expressShow: { // 快递到家服务条款显示标识
type: Boolean,
value: false
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
// 隐藏弹出框
hidePopup: function () {
this.setData({
show: false
})
},
}
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--component/productGuarantee/productGuarantee.wxml-->
<view class="popup-container{{show ? ' active' : ''}}" bindtap="hidePopup"></view>
<view class="popup-content{{show ? ' active' : ''}}">
<view class='top'>
<text class='top-title'>服务</text>
<image class="popup-close" mode="widthFix" src="img/coupon-close.png" bindtap="hidePopup"></image>
</view>
<view class='main-content' catchtouchmove="return" wx:if="{{normalShow}}">
<view class='item'>
<text class='item-title'>• 官方正品保证</text>
<view class='item-detail'>
<view>本店为热风官方微商城,所售商品均热风仓库统一发货,请您放心购买</view>
</view>
</view>
<view class='item'>
<text class='item-title'>• 30天无理由退换</text>
<view class='item-detail'>
<view>1. 商品未经使用、洗涤、损坏的前提下,在购买30天内可无条件退换;</view>
<view>2. 内衣、内裤、袜类、口罩、手帕等涉及人体健康卫生的商品,如非质量问题,一经销售,恕不退货;</view>
</view>
</view>
<view class='item'>
<text class='item-title'>• 满99或2件包邮</text>
<view class='item-detail'>
<view>1. 订单满2件或满99元(不包含运费)免运费;</view>
<view>2. 不满足包邮条件江、浙、沪5元,新疆、西藏、甘肃等偏远地区15元,其他城市10元;</view>
<view>3. 可积分兑换包邮券抵扣邮费;</view>
</view>
</view>
<view class='item'>
<text class='item-title'>• 双倍积分</text>
<view class='item-detail'>
<view>微商城每笔消费订单,签收后获得支付金额的双倍积分(运费不获得积分)</view>
</view>
</view>
</view>
<view class='main-content' catchtouchmove="return" wx:if="{{expressShow}}">
<view class='item'>
<text class='item-title'>• 官方正品保证</text>
<view class='item-detail'>
<view>本店为热风官方店铺,所售商品均热风仓库或热风门店发货,请放心购买;</view>
</view>
</view>
<view class='item'>
<text class='item-title'>• 30天无理由退换</text>
<view class='item-detail'>
<view>1. 商品未经使用、洗涤、损坏的前提下,在购买30天内可无条件退换;</view>
<view>2. 内衣、内裤、袜类、手帕等设计人体健康卫生的商品,如非质量问题,已经销售,恕不退换;;</view>
</view>
</view>
<view class='item' >
<text class='item-title'>• 全国包邮</text>
<view class='item-detail'>
<view>门店缺货扫码购买商品,全国范围内免运费;</view>
</view>
</view>
<view class='item'>
<text class='item-title'>• 双倍积分</text>
<view class='item-detail'>
<view>每笔消费订单,签收后获得支付金额的双倍积分(运费与优惠券抵扣金额不获得积分);</view>
</view>
</view>
</view>
</view>
/* component/productGuarantee/productGuarantee.wxss */
.popup-container {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.5);
transform: translateY(100%);
opacity: 0;
transition: opacity 200ms;
z-index: 98;
}
.popup-container.active {
opacity: 1;
transform: translateY(0); }
.popup-content.active {
transform: translateY(0); }
.popup-content {
position: fixed;
z-index: 99;
width: 100%;
min-height: 400rpx;
bottom: 0;
left: 0;
background: #fff;
transition: transform 300ms;
transform: translateY(100%); }
.top{
display: flex;
flex-direction: row;
align-items: center;
margin: 30rpx 30rpx 25rpx 30rpx;
padding-bottom: 26rpx;
border-bottom: 1rpx solid #f2f2f2;
}
.top-title{
color: #333;
font-size: 28rpx;
}
.top-title-tip{
margin-left: 30rpx;
font-size: 23rpx;
color: #cb3c3c;
}
.popup-content .popup-close {
position: absolute;
right: 30rpx;
top: 30rpx;
width: 30rpx;
height: 30rpx; }
.clearfix::after {
content: '';
display: block;
clear: both; }
.main-content{
margin: 0rpx 30rpx 80rpx 30rpx;
}
.item{
margin-top: 30rpx;
}
.item-title{
font-size: 25rpx;
}
.item-detail view{
color: #676767;
font-size: 24rpx;
}
\ No newline at end of file
// components/swiper/tSwiper.js
Component({
/**
* 组件的属性列表
*/
properties: {
imgUrls: {
type: Array,
value: []
},
config: {
type: Object,
value: {
indicatorDots: true,
autoplay: true,
interval: 2000,
duration: 500,
current: 0,
circular: true,
vertical: false,
indicatorColor: '#e6e6e6',
indicatorActiveColor: '#00833d'
}
}
},
/**
* 组件的初始数据
*/
data: {
imageHeights: {},
current: 0,
sysRes: wx.getSystemInfoSync()
},
/**
* 组件的方法列表
*/
methods: {
// _tap (e) {
// const swiperTapDetail = e.detail // detail对象,提供给事件监听函数
// const swiperTapOption = {
// item: e.currentTarget.dataset.item
// } // 触发事件的选项
// },
bindChange: function (e) {
this.setData({
current: e.detail.current
})
},
imageLoad: function (e) { // 图片加载完成回调
const sysRes = this.data.sysRes
var imageWidth = e.detail.width
var imageHeight = e.detail.height
var ratio = imageWidth / imageHeight
var imageHeights = this.data.imageHeights
imageHeights[e.target.id] = sysRes.windowWidth / ratio
this.setData({
imageHeights: imageHeights
})
}
},
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function () {
if (Object.keys(this.data.config).length > 0) {
this.setData({
...this.data.config
})
}
}
// moved: function () { },
// detached: function () { },
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<!--components/swiper/tSwiper.wxml-->
<view class='swiper-content'>
<swiper
indicator-dots="{{indicatorDots}}"
current="{{current}}"
vertical="{{vertical}}"
autoplay="true" circular="true"
indicator-color="{{indicatorColor}}"
interval="{{interval}}"
bindchange="bindChange"
style="height: 750rpx;"
indicator-active-color="{{indicatorActiveColor}}"
duration="{{duration}}">
<block wx:key="*this" wx:for="{{imgUrls}}">
<swiper-item bindtap="_tap" data-item="{{item}}" >
<image src="{{item}}" id="swiperImg{{index}}" mode="widthFix" class="slide-image" bindload="imageLoad"/>
</swiper-item>
</block>
</swiper>
</view>
<!-- style="height:{{imageHeights['swiperImg' + current]}}px" -->
\ No newline at end of file
/* components/swiper/tSwiper.wxss */
.slide-image {
width: 100%;
}
\ No newline at end of file
{
"navigationBarTitleText": "商品详情",
"usingComponents": {
"t-swiper":"../../components/swiper/tSwiper",
"t-footer": "../../components/footerTip/footerTip",
"add-tip": "../../components/addTips/addTips",
"product-guarantee": "../../components/productGuarantee/productGuarantee",
"x-html": "../../components/html2wxml/wxHtml"
}
}
\ No newline at end of file
<import src="../temp/loading.wxml" />
<import src="../temp/header.wxml" />
<import src="../wxParser/index.wxml" />
<add-tip isFirst="{{isFirst}}" bind:closeTips="closeTips" />
<template is="loadding" data="{{loadingShow}}" />
<view style='padding-bottom:120rpx;' wx:if="{{!loadingShow}}" class="product-container" bindtouchstart="pageTouchStart" bindtouchmove="pageMove" bindtouchend="pageMoveEnd">
<swiper indicator-dots="{{showDot}}" indicator-color="rgba(0, 0, 0, 0.2)" indicator-active-color="#00843e" autoplay="true" style="height: 750rpx;">
<block wx:for="{{images}}" wx:key="index">
<swiper-item>
<image class="swiper-image" mode="widthFix" src="{{item}}"></image>
</swiper-item>
</block>
</swiper>
<view class="pro-info">
<view class="info">
<view class="price-info">
<text class="price">
<text class='rmb-unit'>¥</text>
{{goodInfo.price}}
</text>
</view>
</view>
<view class="pro-name">{{goodInfo.name}}{{goodInfo.girard}}</view>
<view class='promotion-wapper' wx:if="{{goodInfo.promotionName}}">
<view>
<text class='promotion-info'>{{goodInfo.promotionName}}</text>
</view>
</view>
</view>
<view class="other-info">
<view class="to-choose">
<text class='spec-name'>规格:</text>
<view class="to-choose-right">
<text class='spec-name'>已选 "{{goodInfo.colorName}}##{{goodInfo.sizeName}}"</text>
</view>
</view>
</view>
<view class='product-guarantee' bindtap='showProGuarantee'>
<view class='pro-g'>
<image src='https://img3.bigaka.com/prd/3001/202005/20200513/3001e41bc04b-bec3-47c8-bcf7-e1ad07cf30e1.png' mode="widthFix" class='pro-g-icon'></image>
<text>官方正品保证</text>
</view>
<view class='pro-g'>
<image src='https://img3.bigaka.com/prd/3001/202005/20200513/3001e41bc04b-bec3-47c8-bcf7-e1ad07cf30e1.png' mode="widthFix" class='pro-g-icon'></image>
<text>30天无理由退换</text>
</view>
<view class='pro-g'>
<image src='https://img3.bigaka.com/prd/3001/202005/20200513/3001e41bc04b-bec3-47c8-bcf7-e1ad07cf30e1.png' mode="widthFix" class='pro-g-icon'></image>
<text>全国包邮</text>
</view>
<view class='pro-g'>
<image src='https://img3.bigaka.com/prd/3001/202005/20200513/3001e41bc04b-bec3-47c8-bcf7-e1ad07cf30e1.png' mode="widthFix" class='pro-g-icon'></image>
<text>双倍积分</text>
</view>
<view>
<image src='https://hwimagecdn.ihotwind.cn/hotwind-mini/images/usercenter/uc-rg-arrow.png' mode="widthFix" style='width:13rpx;'></image>
</view>
</view>
<view class="scroll-tips" wx:if="{{htmlContent == null}}">{{scrollTips}}</view>
<block wx:if="{{showHtml}}">
<view wx:if="{{goodInfo.imgAdIsOpen}}">
<view wx:if="{{goodInfo.imgHtmlLocation == 1}}">
<view class="wxParser">
<template is="wxParser" data="{{wxParserData:article.nodes}}" />
</view>
</view>
<x-html html="{{goodInfo.htmlText}}" />
<view wx:if="{{goodInfo.imgHtmlLocation == 2}}">
<view class="wxParser">
<template is="wxParser" data="{{wxParserData:article.nodes}}" />
</view>
</view>
</view>
<view wx:if="{{!goodInfo.imgAdIsOpen}}">
<x-html html="{{goodInfo.htmlText}}" />
</view>
</block>
</view>
<view class="product-footer">
<view class="footer-icons clearfix">
<form class='get-formId' bindsubmit="nav" report-submit name='home'>
<button class="get-formId--btn footer-icon" open-type="contact" session-from="udesk|{{udesk.nick_name}}|{{udesk.avatar}}" send-message-title="{{goodInfo.name}}{{goodInfo.girard}}" show-message-card="true" send-message-img="{{images[0]}}">
<image src="https://hwimagecdn.ihotwind.cn/hotwind-mini/images/hotnewicon/bottom-kefu.png" mode="widthFix"></image>
<view class="tab-text">客服</view>
</button>
</form>
<block wx:if="{{!pageIsAuth}}">
<view class='get-formId'>
<view class=''>
<button bindgetuserinfo="_getUserInfo" data-jflag="false" open-type='getUserInfo' class='getuserinfo_btn footer-icon' hover-class="btn-hover" style="background-color:transparent">
<text class='car-num' wx:if="{{carNum}}">{{carNum}}</text>
<image class="contact-share-img" src="https://hwimagecdn.ihotwind.cn/hotwind-mini/images/hotnewicon/bottom-shop-cart.png" />
<view class="add-car-text">购物车</view>
</button>
</view>
</view>
</block>
<block wx:else>
<view class='get-formId' bindtap='toCar'>
<view class='footer-icon'>
<text class='car-num' wx:if="{{carNum}}">{{carNum}}</text>
<image class="contact-share-img" src="https://hwimagecdn.ihotwind.cn/hotwind-mini/images/hotnewicon/bottom-shop-cart.png" />
<view class="add-car-text">购物车</view>
</view>
</view>
</block>
</view>
<view class="footer-buttons">
<block wx:if="{{!pageIsAuth}}">
<button bindgetuserinfo="_getUserInfo" data-jflag="false" open-type='getUserInfo' class='getuserinfo_btn cart-button' hover-class="btn-hover">
<view class=''>加入购物车</view>
</button>
</block>
<block wx:else>
<button class="cart-button get-formId--btn" bindtap='addGood'>加入购物车</button>
</block>
<block wx:if="{{!pageIsAuth}}">
<button bindgetuserinfo="_getUserInfo" data-jflag="false" open-type='getUserInfo' class='getuserinfo_btn buy-button' hover-class="btn-hover">
<view class=''>立即购买</view>
</button>
</block>
<block wx:else>
<button class="buy-button get-formId--btn" bindtap='buyNow'>立即购买</button>
</block>
</view>
</view>
<view class="pro-detail-popup">
<view class="service-content" bindtap="scan" style="border-radius:50%;overflow:hidden;">
<image class="contact-share-img" src="https://hwimagecdn.ihotwind.cn/hotwind-mini/images/kuaididaojia/saoma-icon.png"></image>
</view>
<view class="service-content" bindtap="returnTop">
<image class="contact-share-img" src="https://hwimagecdn.ihotwind.cn/hotwind-mini/images/kuaididaojia/return-top-icon.png"></image>
</view>
</view>
<!-- 库存不足 -->
<view class="mask {{stock ? 'active' : 'hide'}}">
<view class='reason'>您购买的【{{goodInfo.name}}】,库存不足。</view>
<view class='maskBtn' bindtap='closeMask'>我知道了</view>
</view>
<product-guarantee wx:if="{{showProGuarantee}}" show="{{showProGuarantee}}" express-show="{{true}}" />
\ No newline at end of file
/**index.wxss**/
.banner-jpg {
width: 100%;
height: 175rpx;
}
.container-detail {
padding: 53rpx 0 46rpx 0;
}
.goodsDetail {
padding: 0 0 29rpx 55rpx;
}
.detail-title {
padding: 0 0 18rpx 55rpx;
}
.detail-box {
padding: 0 0 48rpx 55rpx;
}
.detail-size {
float: left;
margin-right: 90rpx;
}
.detail-color {
float: left;
margin-right: 70rpx;
}
.detail-money {
padding-left: 52rpx;
color: #d10d16;
font-size: 40rpx;
}
.edit-box {
margin-top: 5rpx;
padding: 26rpx 0 52rpx 35rpx;
background-color: #fff;
height: 550rpx;
/* width: 100%; */
}
.edit-title {
margin-bottom: 31rpx;
font-size: 36rpx;
color: #313131;
}
.edit-color {
margin: 31rpx 0 21rpx;
font-size: 36rpx;
color: #313131;
}
.color-title {
margin-bottom: 21rpx;
}
.color-box {
/* height: 50rpx; */
}
.edit-color .choose-color {
display: block;
float: left;
width: 170rpx;
height: 50rpx;
margin-right: 30rpx;
text-align: center;
border: 1px solid #7b7b7b;
color: #7b7b7b;
font-size: 30rpx;
line-height: 50rpx;
border-radius: 10rpx;
box-sizing: border-box;
margin-bottom: 15rpx;
}
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.edit-size {
margin: 40rpx 0 21rpx;
font-size: 36rpx;
color: #313131;
}
.size-title {
margin-bottom: 22rpx;
}
.size-box {
/* height: 100rpx; */
}
.edit-size .choose-size {
display: block;
float: left;
width: 135rpx;
height: 50rpx;
margin-right: 30rpx;
text-align: center;
border: 1px solid #7b7b7b;
color: #7b7b7b;
font-size: 30rpx;
line-height: 50rpx;
border-radius: 10rpx;
margin-bottom: 20rpx;
}
.footer-btn {
position: fixed;
left: 0;
bottom: 0;
display: flex;
height: 90rpx;
font-size: 40rpx;
width: 100%;
}
.addCar, .buyNow {
flex: 1;
text-align: center;
line-height: 90rpx;
color: #fff;
border-radius: 0 !important;
}
.addCar {
background-color: #69b8b5;
}
.buyNow {
background-color: #ffa334;
}
.toCar {
position: fixed;
bottom: 154rpx;
right: 20rpx;
background-color: transparent;
z-index: 999;
}
.carPng {
width: 90rpx;
height: 90rpx;
}
.getuserinfo_btn.toCar{
border-radius: 50%;
bottom: 158rpx;
}
.toSweep {
position: fixed;
bottom: 154rpx;
right: 130rpx;
background-color: transparent;
}
.sweep-icon {
width: 90rpx;
height: 90rpx;
}
.choosen {
position: relative;
border: none !important;
}
.color-choosen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.blank {
width: 100%;
height: 500rpx;
}
.mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: #000;
opacity: 0.8;
}
.mask.hide {
display:none;
opacity: 0;
transition: opacity .2s ease;
}
.reason {
margin: 380rpx 55rpx 0;
color: #fff;
font-size: 36rpx;
}
.maskBtn {
margin: 94rpx auto;
color: #fff;
font-size: 40rpx;
text-align: center;
width: 370rpx;
height: 100rpx;
border: 2px solid #fff;
line-height: 100rpx;
border-radius: 10rpx;
}
.name {
min-height: 80rpx;
padding: 20rpx 45rpx;
background-color: #fff;
margin-top: 10rpx;
display: flex;
justify-content: flex-start;
align-items: center;
box-sizing: border-box;
}
.index-png {
width: 30rpx;
height: 30rpx;
margin: 0 20rpx 0 0;
}
.index-title {
color: #434343;
font-size: 30rpx;
margin: 0 70rpx 0 0;
}
.index-detail {
color: #959595;
font-size: 30rpx;
}
/* .car-num {
position: fixed;
bottom: 220rpx;
right: 20rpx;
padding: 0 9rpx;
font-size: 24rpx;
box-sizing: border-box;
background-color:red;
border-radius:50%;
color: #fff;
z-index:1;
} */
.car-num {
position: fixed;
bottom: 65rpx;
left: 190rpx;
width: 32rpx;
height: 32rpx;
line-height: 32rpx;
font-size: 20rpx;
box-sizing: border-box;
background-color:red;
border-radius:50%;
color: #fff;
z-index:1;
text-align: center;
}
.pro-info {
padding: 30rpx 25rpx 20rpx 25rpx;
background-color:#fff;
position: relative; }
.pro-info .info .pro-name {
font-size: 30rpx;
color: #121212;
}
.pro-info .info .spec-info {
margin-bottom: 10rpx; }
.pro-info .other-info {
padding: 1rpx 5rpx; }
.pro-info .spec-info {
margin: 10rpx 0; }
.pro-info .spec-info .spec-name {
color: #999999; }
.pro-info .spec-info .spec-value {
color: #666666; }
.pro-info .price {
color: #DC0E30;
font-size: 44rpx;
line-height: 60rpx; }
.other-info {
border-top: 1rpx solid #e6e6e6;
margin-top: 20rpx;
padding: 0rpx 25rpx 0rpx 25rpx;
background-color: #fff;
}
.other-info .spec-name{
font-size: 25rpx;
color: #999999;
}
.other-info .spec-value{
font-size: 25rpx;
color: #666666;
}
.product-footer {
position: fixed;
background: #F7F7FA;
height: 100rpx;
left: 0;
right:0;
bottom: 0;
width: 100%;
z-index: 2;
display: flex;
flex-direction: row; }
.product-footer .footer-icons {
width: 240rpx;
flex-grow: 0;
border-top: 2rpx solid #eeeeee; }
.product-footer .footer-icons .footer-icon {
width: 50%;
box-sizing: border-box;
float: left;
height: 100rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center; }
.product-footer .footer-icons .footer-icon:first-child {
border-right: 2rpx solid #eeeeee; }
.product-footer .footer-icons .footer-icon image {
width: 39rpx;
height: 39rpx;
flex-shrink: 0; }
.product-footer .footer-icons .footer-icon view {
font-size: 20rpx;
line-height: 22rpx;
color: #333333;
margin-top: 8rpx; }
.product-footer .footer-buttons {
flex: 1;
display: flex;
height: 100rpx;
}
.product-footer .footer-buttons button {
flex: 1;
font-size: 30rpx;
line-height: 100rpx;
border-radius: 0;
color: #ffffff; }
.product-footer .footer-buttons button[disabled] {
background: #cccccc; }
.product-footer .footer-buttons button.cart-button {
background: #39b99e; }
.product-footer .footer-buttons button.buy-button {
background: #007d63; }
.product-footer .footer-buttons button::after {
border: 0; }
.product-footer .footer-buttons button.button-hover {
opacity: 0.5; }
.pro-detail-popup {
height: 288rpx;
width: 96rpx;
position: fixed;
top: 76%;
right: 0;
z-index: 20;
margin-right:18rpx;
}
.pro-detail-popup-img{
height: 288rpx;
width: 110rpx;
position: fixed;
top: 52%;
right: 0;
z-index: 20;
margin-right:18rpx;
}
.share-content,.car-content,.service-content{
text-align: center;
}
.return-top{
position:fixed;
top:80%;
right:0;
z-index:9;
}
.return-top-img{
width: 75rpx;
}
.contact-share-img {
width: 75rpx;
height: 75rpx;
}
.product-guarantee{
display: flex;
direction: row;
height: 70rpx;
line-height: 70rpx;
background-color: #fff;
margin-top: 20rpx;
padding: 0 40rpx 0 40rpx;
}
.pro-g{
margin-right: 20rpx;
}
.pro-g text{
color:#999999;
font-size: 20rpx;
}
.pro-g-icon{
width: 14rpx;
margin-right: 10rpx;
}
.scroll-tips {
line-height: 100rpx;
border-top: 2rpx solid #eaeaea;
text-align: center;
font-size: 28rpx; }
.to-choose{
min-height: 60rpx;
background-color: #fff;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
/* justify-content: space-between; */
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.to-choose-right text {
padding-right: 25rpx;
position: relative;
}
.spec-name {
color: #999999; }
.other-info {
margin-top: 20rpx;
padding: 0rpx 25rpx 0rpx 25rpx;
background-color: #fff;
}
.swiper-image{
width: 100%;
}
.promotion-wapper{
background-color: #FBF1F0;
padding: 20rpx;
margin: 18rpx 0;
}
.promotion-info{
font-size: 24rpx;
color: #DC0E30;
}
\ No newline at end of file
/**
* 特殊字符映射表
* @type {Object}
*/
const codeMap = {
// HTML 支持的数学符号
'&forall;': '∀',
'&part;': '∂',
'&exists;': '∃',
'&empty;': '∅',
'&nabla;': '∇',
'&isin;': '∈',
'&notin;': '∉',
'&ni;': '∋',
'&prod;': '∏',
'&sum;': '∑',
'&minus;': '−',
'&lowast;': '∗',
'&radic;': '√',
'&prop;': '∝',
'&infin;': '∞',
'&ang;': '∠',
'&and;': '∧',
'&or;': '∨',
'&cap;': '∩',
'&cap;': '∪',
'&int;': '∫',
'&there4;': '∴',
'&sim;': '∼',
'&cong;': '≅',
'&asymp;': '≈',
'&ne;': '≠',
'&le;': '≤',
'&ge;': '≥',
'&sub;': '⊂',
'&sup;': '⊃',
'&nsub;': '⊄',
'&sube;': '⊆',
'&supe;': '⊇',
'&oplus;': '⊕',
'&otimes;': '⊗',
'&perp;': '⊥',
'&sdot;': '⋅',
// HTML 支持的希腊字母
'&Alpha;': 'Α',
'&Beta;': 'Β',
'&Gamma;': 'Γ',
'&Delta;': 'Δ',
'&Epsilon;': 'Ε',
'&Zeta;': 'Ζ',
'&Eta;': 'Η',
'&Theta;': 'Θ',
'&Iota;': 'Ι',
'&Kappa;': 'Κ',
'&Lambda;': 'Λ',
'&Mu;': 'Μ',
'&Nu;': 'Ν',
'&Xi;': 'Ν',
'&Omicron;': 'Ο',
'&Pi;': 'Π',
'&Rho;': 'Ρ',
'&Sigma;': 'Σ',
'&Tau;': 'Τ',
'&Upsilon;': 'Υ',
'&Phi;': 'Φ',
'&Chi;': 'Χ',
'&Psi;': 'Ψ',
'&Omega;': 'Ω',
'&alpha;': 'α',
'&beta;': 'β',
'&gamma;': 'γ',
'&delta;': 'δ',
'&epsilon;': 'ε',
'&zeta;': 'ζ',
'&eta;': 'η',
'&theta;': 'θ',
'&iota;': 'ι',
'&kappa;': 'κ',
'&lambda;': 'λ',
'&mu;': 'μ',
'&nu;': 'ν',
'&xi;': 'ξ',
'&omicron;': 'ο',
'&pi;': 'π',
'&rho;': 'ρ',
'&sigmaf;': 'ς',
'&sigma;': 'σ',
'&tau;': 'τ',
'&upsilon;': 'υ',
'&phi;': 'φ',
'&chi;': 'χ',
'&psi;': 'ψ',
'&omega;': 'ω',
'&thetasym;': 'ϑ',
'&upsih;': 'ϒ',
'&piv;': 'ϖ',
'&middot;': '·',
// 常用解析
'&nbsp;': ' ',
'&quot;': "'",
'&amp;': '&',
'&lt;': '<',
'&gt;': '>',
// HTML 支持的其他实体
'&OElig;': 'Œ',
'&oelig;': 'œ',
'&Scaron;': 'Š',
'&scaron;': 'š',
'&Yuml;': 'Ÿ',
'&fnof;': 'ƒ',
'&circ;': 'ˆ',
'&tilde;': '˜',
'&ensp;': '',
'&emsp;': '',
'&thinsp;': '',
'&zwnj;': '',
'&zwj;': '',
'&lrm;': '',
'&rlm;': '',
'&ndash;': '–',
'&mdash;': '—',
'&lsquo;': '‘',
'&rsquo;': '’',
'&sbquo;': '‚',
'&ldquo;': '“',
'&rdquo;': '”',
'&bdquo;': '„',
'&dagger;': '†',
'&Dagger;': '‡',
'&bull;': '•',
'&hellip;': '…',
'&permil;': '‰',
'&prime;': '′',
'&Prime;': '″',
'&lsaquo;': '‹',
'&rsaquo;': '›',
'&oline;': '‾',
'&euro;': '€',
'&trade;': '™',
'&larr;': '←',
'&uarr;': '↑',
'&rarr;': '→',
'&darr;': '↓',
'&harr;': '↔',
'&crarr;': '↵',
'&lceil;': '⌈',
'&rceil;': '⌉',
'&lfloor;': '⌊',
'&rfloor;': '⌋',
'&loz;': '◊',
'&spades;': '♠',
'&clubs;': '♣',
'&hearts;': '♥',
'&diams;': '♦',
'&#39;': "'"
};
/**
* 转换特殊字符
* @param {String} str 待转换字符串
* @return {String} 转换后的字符串
*/
const transform = (str) => {
for (let code in codeMap) {
str = str.replace(new RegExp(code, 'g'), codeMap[code]);
}
return str;
};
module.exports = {
transform
}
const utils = require('./utils');
const makeMap = utils.makeMap;
module.exports = {
empty: makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'),
block: makeMap('br,a,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'),
inline: makeMap('abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'),
closeSelf: makeMap('br,hr'),
fillAttrs: makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'),
special: makeMap('script,style')
};
const utils = require('./utils');
const elements = require('./elements');
const codeTransformation = require('./codeTransformation');
const htmlParser = require('./htmlparser');
let olTagCount = [];
/**
* 移除文档头信息
* @param {String} str HTML 内容
* @return {String}
*/
const removeDOCTYPE = (str) => {
return str.replace(/<\?xml.*\?>\n/, '').replace(/<.*!doctype.*\>\n/, '').replace(/<.*!DOCTYPE.*\>\n/, '');
};
/**
* HTML 内容转化为 JSON 格式的对象
* @param {String} html HTML 内容
* @param {String} bindName 绑定的数据名
* @return {Object}
*/
const html2json = (html, bindName) => {
html = removeDOCTYPE(html);
// 节点缓冲区,与 htmlparser.js 中的 stack 对应,只存储非自闭和标签
// 比如 <span></span>,而非 <img src="#"> 等
let bufferNodes = [];
let nodeStyles = [];
// html2json 结果
let results = {
nodes: [],
images: [],
imageUrls: []
};
/**
* 把节点放到父节点的 nodes 列表
* @param {Object} node 节点对象
*/
const putNode2ParentNodeList = (node) => {
if (bufferNodes.length === 0) { // 表明关闭此 node 时,不存在任何未关闭标签,也就是不存在父元素,所以直接挂到根节点即可
results.nodes.push(node);
} else {
// 如果节点缓冲区还有节点,子节点会不断的被放到该子节点的父节点下,形成一个嵌套引用的节点对象。
// 直到缓冲区没有节点,此时组装起来的整个嵌套引用节点对象会被放到根节点的 results.nodes 下
let parent = bufferNodes[0]; // 取该 node 的父级节点
if (parent.nodes === undefined) {
parent.nodes = [];
}
node.parent = parent.tag
parent.nodes.push(node);
}
};
// 开始解析 HTML
// 核心思路:
// 1、遇到开始标签时,如果该标签是非自闭合标签,就把该节点存到缓存区(入栈),
// 如果是自闭合标签、空标签等就直接存到根节点下(因为这种几点没有子节点)。
// 2、当遇到文本时(文本也是节点),判断缓冲区是否还有节点,如果有,证明该节点有父节点,
// 需要把此节点放到父节点的 nodes 列表,如果没有,则证明该节点没有父节点了,放到根节点即可。
// 3、当遇到结束标签时,就从缓存区取出第一个节点(出栈),比较是否与该结束标签对应,
// 如果不对应,证明逻辑出错。如果对应,则判断缓冲区是否还有节点,如果有,证明该节点有父节点,
// 需要把此节点放到父节点的 nodes 列表,如果没有,则证明该节点没有父节点了,放到根节点即可。
//
// 总体来说,就是一个进栈出栈(节点缓冲区)的算法问题。
htmlParser.parseHtml(html, {
/**
* 处理开始标签
* @param {String} tag 标签名称
* @param {Array} attrs 属性
* @param {Boolean} isUnary 是否是自闭合标签
*/
start: function (tag, attrs, isUnary) {
let node = {
node: 'element',
tag: tag
};
if (elements.block[tag]) {
node.tagType = 'block';
} else if (elements.inline[tag]) {
node.tagType = 'inline';
} else if (elements.closeSelf[tag]) {
node.tagType = 'closeSelf';
}
nodeStyles = [];
if (attrs.length) {
node.attr = {};
attrs.map((item) => {
if (item.name === 'style') { // 对 style 做单独处理,因为后面会根据 tag 添加更多的 style
if (nodeStyles.indexOf(item.value) === -1) {
nodeStyles.push(item.value);
}
}
if (item.name === 'color') {
nodeStyles.push('color: ' + item.value);
}
if (node.tag === 'font' && item.name === 'size') {
nodeStyles.push('font-size: ' + utils.getFontSizeByAttribsSize(item.value));
}
// 特殊属性做转换
if (item.name === 'class') {
node.classStr = item.value;
}
node.attr[item.name] = item.value; // 重复的属性,后面的会覆盖前面的
});
node.styleStr = nodeStyles.join(' ');
}
if (node.tag == 'ol' || node.tag == 'ul') {
olTagCount.push(0)
}
if (node.tag == 'li') {
let len = olTagCount.length - 1
olTagCount[len] = olTagCount[len] + 1
node.order = olTagCount[len]
}
// img 标签 添加额外数据
if (node.tag === 'img') {
node.imgIndex = results.images.length;
node.from = bindName;
results.images.push(node);
results.imageUrls.push(node.attr.src);
}
if (node.tag === 'video' || node.tag === 'audio') {
node.attr.controls = !node.attr.controls ? false : true
node.attr.autoplay = !node.attr.autoplay ? false : true
node.attr.loop = !node.attr.loop ? false : true
}
if (node.tag === 'video') {
node.attr.muted = !node.attr.muted ? false : true
}
if (node.tag === 'audio') {
let params = node.attr['data-extra']
if (params) {
params = params.replace(new RegExp('&quot;', 'g'), '"');
params = JSON.parse(params)
node.attr.poster = params.poster
node.attr.name = params.name
node.attr.author = params.author
}
}
if (isUnary) {
// 自闭合标签,比如 <img src="https://github.com/pacochan/wxParser.png"/>
// 这种类型不会进入 end 函数或者 text 函数处理,在 start 函数放入到父元素的 nodes 列表即可
putNode2ParentNodeList(node);
} else {
// 只要有非自闭&标签就往缓冲区保存节点,等待关闭
bufferNodes.unshift(node);
}
},
/**
* 处理关闭标签
* @param {String} tag 标签名称
*/
end: function (tag) {
let node = bufferNodes.shift(); // 取出缓冲区的第一个的未关闭标签,也就是与该结束标签对应的标签
if (node.tag !== tag) {
throw new Error('不匹配的关闭标签');
}
if (node.tag == 'ol' || node.tag == 'ul') {
olTagCount.pop()
}
if (node.tag === 'video' || node.tag === 'audio') {
if (!node.attr.src) {
let nodes = node.nodes
let len = nodes.length
let src = ''
for (let i = 0; i < len; i++) {
if (nodes[i].tag === 'source') {
src = nodes[i].attr.src
break
}
}
node.attr.src = src
}
}
putNode2ParentNodeList(node);
},
/**
* 处理文本内容
* @param {String} text 文本字符串
*/
text: function (text) {
let node = {
node: 'text',
text: codeTransformation.transform(text),
};
putNode2ParentNodeList(node);
},
/**
* 处理评论内容
* @param {String} content 注释内容
*/
comment: function (content) {},
});
return results;
};
module.exports = {
html2json
};
const elements = require('./elements');
const startTagReg = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
const endTagReg = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
const attrReg = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
/**
* 解析 HTML
* @param {String} html HTML 内容
* @param {Object} handler 处理器
*/
const parseHtml = (html, handler) => {
let index;
let isText;
let match;
let stack = [];
let last = html;
// 只存放非自闭合普通标签,不存放空标签、特殊标签和自闭合标签
stack.last = function () {
return this[this.length - 1];
};
while (html) {
isText = true;
if (!stack.length || !elements.special[stack.last()]) {
if (html.indexOf('<!--') === 0) { // comment
index = html.indexOf('-->'); // indexOf 会匹配到第一个满足条件的字符位置
if (index !== -1) {
if (handler.comment) {
// 因为注释信息不会像其他标签那样包含内部标签,所以可以直接传注释内容给 handler 处理
handler.comment(html.substring(4, index));
}
html = html.substring(index + 3);
isText = false;
}
} else if (html.indexOf('</') === 0) { // end tag
match = html.match(endTagReg);
if (match) {
html = html.substring(match[0].length);
match[0].replace(endTagReg, parseEndTag);
isText = false;
}
} else if (html.indexOf('<') === 0) { // start tag
match = html.match(startTagReg);
if (match) {
html = html.substring(match[0].length);
match[0].replace(startTagReg, parseStartTag);
isText = false;
}
}
// 处理文本内容
if (isText) {
index = html.indexOf('<');
let text = ''
while (index === 0 && !html.match(startTagReg)) { // 处理以 < 开头,但是却不满足 startTagReg 的情况
text += '<';
html = html.substring(1);
index = html.indexOf('<');
}
text += index < 0 ? html : html.substring(0, index);
html = index < 0 ? '' : html.substring(index);
if (handler.text) {
handler.text(text);
}
}
} else {
html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {
// 丢弃 special tag 内部的所有内容,包括该 special tag 的闭合标签
return '';
});
}
if (html === last) {
throw new Error('解析 html 内容时出席异常');
}
last = html;
}
if (stack.length) {
throw new Error('HTML 内容存在未关闭的标签,会导致未关闭标签的内容无法被解析');
}
/**
* 解析开始标签
* @param {String} match 匹配结果
* @param {String} tagName 标签名称
* @param {String} attrsStr 属性信息
* @param {String} unary
*/
function parseStartTag(match, tagName, attrsStr, unary) {
// 举例:
// match: <p style="text-align: center; " width="100">
// tagName: p
// attrsStr: style="text-align: center; " width="100"
tagName = tagName.toLowerCase();
let isUnary = elements.empty[tagName] || unary;
// 空标签、自闭和标签、特殊标签不需要进 stack
if (!isUnary && !elements.closeSelf[tagName] && !elements.special[tagName]) {
stack.push(tagName);
}
if (handler.start && !elements.special[tagName]) {
let attrs = [];
attrsStr.replace(attrReg, function (match, name, value) {
if (elements.fillAttrs[name]) {
value = name;
}
attrs.push({
name: name,
value: value || '',
});
});
handler.start(tagName, attrs, isUnary);
}
}
/**
* 解析结束标签
* @param {String} match 匹配结果
* @param {String} tagName 标签名称
*/
function parseEndTag(match, tagName) {
if (!tagName) {
return;
}
// 找到最近同种类型的未关闭标签的位置
tagName = tagName.toLowerCase();
let closestOpenedTagPos = -1;
for (let pos = stack.length - 1; pos >= 0; pos--) {
if (stack[pos] == tagName) {
closestOpenedTagPos = pos;
break;
}
}
if (closestOpenedTagPos >= 0) {
if (handler.end) {
handler.end(stack[closestOpenedTagPos]);
}
// 处理后从 stack 中移除该标签
stack.length = closestOpenedTagPos;
}
}
};
module.exports = {
parseHtml
};
const html2Json = require('./html2json');
/**
* 主解析函数
* @param {Object} options 配置参数
* @param {String} [options.bind=wxParserData] 绑定的变量名
* @param {String} options.html HTML 内容
* @param {Object} options.target 要绑定的模块对象
* @param {Boolean} [options.enablePreviewImage=true] 是否启用预览图片功能
* @param {Function} [options.tapLink] 点击超链接后的回调函数
*/
const parse = ({ bind = 'wxParserData', html, target, enablePreviewImage = true, tapLink }) => {
if (Object.prototype.toString.call(html) !== '[object String]') {
throw new Error('HTML 内容必须是字符串');
}
let that = target;
let transData = {}; // 存放转化后的数据
transData = html2Json.html2json(html, bind);
let bindData = {};
bindData[bind] = transData;
that.setData(bindData)
// 加载图片后回调函数
that.loadedWxParserImg = (e) => {
};
// 点击图片
that.tapWxParserImg = (e) => {
if (!enablePreviewImage) {
return;
}
let src = e.target.dataset.src;
let tagFrom = e.target.dataset.from;
if (typeof (tagFrom) !== 'undefined' && tagFrom.length > 0) {
wx.previewImage({
current: src, // 当前显示图片的 http 链接
urls: that.data[tagFrom].imageUrls // 需要预览的图片 http 链接列表
})
}
};
// 点击超链接
if (Object.prototype.toString.call(tapLink) === '[object Function]') {
that.tapWxParserA = (e) => {
let href = e.currentTarget.dataset.href;
tapLink(href);
};
}
};
module.exports = {
parse
}
This source diff could not be displayed because it is too large. You can view the blob instead.
@charset "UTF-8";
/**
* wxParser 基础样式
*/
.wxParser-div,
.wxParser-p {
word-break: break-all;
overflow: auto;
max-width: 100%; }
.wxParser-inline {
display: inline;
margin: 0;
padding: 0; }
.wxParser-div {
margin: 0;
padding: 0; }
.wxParser-p {
/* margin: 5rpx 0; */
}
.wxParser-br {
height: 0.4em; }
.wxParser-h1 {
font-size: 2em;
margin: .67em 0; }
.wxParser-h2 {
font-size: 1.5em;
margin: .75em 0; }
.wxParser-h3 {
font-size: 1.17em;
margin: .83em 0; }
.wxParser-h4 {
margin: 1.12em 0; }
.wxParser-h5 {
font-size: .83em;
margin: 1.5em 0; }
.wxParser-h6 {
font-size: .75em;
margin: 1.67em 0; }
.wxParser-h1,
.wxParser-h2,
.wxParser-h3,
.wxParser-h4,
.wxParser-h5,
.wxParser-h6,
.wxParser-b,
.wxParser-strong {
font-weight: bolder; }
.wxParser-i,
.wxParser-cite,
.wxParser-em,
.wxParser-var,
.wxParser-address {
font-style: italic; }
.wxParser-pre,
.wxParser-tt,
.wxParser-code,
.wxParser-kbd,
.wxParser-samp {
font-family: monospace; }
.wxParser-pre {
white-space: pre; }
.wxParser-big {
font-size: 1.17em; }
.wxParser-small,
.wxParser-sub,
.wxParser-sup {
font-size: .83em; }
.wxParser-sub {
vertical-align: sub; }
.wxParser-sup {
vertical-align: super; }
.wxParser-s,
.wxParser-strike,
.wxParser-del {
text-decoration: line-through; }
.wxParser-strong,
.wxParser-s {
display: inline; }
.wxParser-u {
text-decoration: underline; }
.wxParser-u {
text-decoration: underline; }
.wxParser-a {
color: deepskyblue;
word-break: break-all;
overflow: auto; }
.wxParser-video {
text-align: center;
margin: 10rpx 0; }
.wxParser-video-video {
width: 100%; }
.wxParser-audio {
text-align: center;
margin: 10rpx 0; }
.wxParser-audio-audio {
display: flex;
flex-direction: column;
text-align: left; }
.wxParser-img {
overflow: hidden;
max-width: 100%; }
.wxParser-blockquote {
margin: 0;
padding: 8rpx 20rpx 8rpx 20rpx;
font-family: Courier, Calibri, "宋体";
background: #f5f5f5;
border-left: 3rpx solid #dbdbdb; }
.wxParser-ul {
margin: 20rpx 10rpx; }
.wxParser-li {
margin: 10rpx 0; }
.wxParser-li,
.wxParser-li-inner {
display: flex;
align-items: baseline; }
.wxParser-li-text {
align-items: center;
line-height: 1em; }
.wxParser-li-circle {
display: inline-flex;
width: 10rpx;
height: 10rpx;
background-color: #333;
margin-right: 12rpx;
border-radius: 50%; }
.wxParser-li-square {
display: inline-flex;
width: 10rpx;
height: 10rpx;
background-color: #333;
margin-right: 5rpx; }
.wxParser-li-ring {
display: inline-flex;
width: 10rpx;
height: 10rpx;
border: 2rpx solid #333;
border-radius: 50%;
background-color: #fff;
margin-right: 5rpx; }
.wxParser-ol {
margin: 20rpx 10rpx; }
.wxParser-ol-li {
margin: 10rpx 0; }
.wxParser-ol-li,
.wxParser-ol-li-inner {
display: flex;
align-items: baseline; }
.wxParser-ol-li-text {
margin-right: 12rpx;
line-height: 1em; }
.wxParser-hidden {
display: none; }
.wxParser-tr {
display: flex;
border-right: 1rpx solid #e0e0e0; }
.wxParser-th,
.wxParser-td {
flex: 1;
padding: 5rpx;
font-size: 28rpx;
border-left: 1rpx solid #e0e0e0;
border-top: 1rpx solid #e0e0e0;
word-break: break-all; }
.wxParser-tr:last-child {
border-bottom: 1rpx solid #e0e0e0; }
.wxParser-th {
background: #f0f0f0; }
.wxParser-hr {
border: 1rpx solid #DDD;
margin: 20rpx 0; }
.wxParser-pre, .wxParser-code {
margin: 5rpx 0;
padding: 10rpx 10rpx;
border-radius: 8rpx;
background: #f8f8f8;
font-size: 30rpx;
line-height: 40rpx;
overflow-x: auto; }
module.exports = {
/**
* 生成 Map
* @param {String} str 以逗号分隔的字符串
* @return {Object} 映射表
*/
makeMap: (str) => {
let map = {};
let items = str.split(',');
for (let i = 0, len = items.length; i < len; i++) {
map[items[i]] = true;
}
return map;
},
/**
* 根据 size 属性得到字体大小
* @param {Number|String} size
* @return {String}
*/
getFontSizeByAttribsSize: function (size) {
var fontSize;
size = parseInt(size, 10);
switch (size) {
case 2:
fontSize = 0.75;
break;
case 3:
fontSize = 1;
break;
case 4:
fontSize = 1.17;
break;
case 5:
fontSize = 1.5;
break;
case 6:
fontSize = 2;
break;
case 7:
fontSize = 3;
break;
default:
fontSize = 1;
}
return fontSize + 'em';
},
}
......@@ -25,8 +25,9 @@
</view>
<view class="menu-list">
<view wx:for="{{secondCategory}}" wx:key="*this" wx:for-index="k" wx:for-item="second" class="menu-third">
<view data-id="{{second.id}}" data-name="{{second.label}}"
<view data-name="{{second.label}}"
data-id="{{second.id}}"
data-item="{{second}}"
data-label="{{second.label}}"
bindtap="onTapToGoodsList">
<image src="{{second.image ? second.image : defaultCategoryImg}}" class="thr-menu-image" mode="aspectFill"/>
......@@ -39,14 +40,16 @@
<view class="second-category" wx:if="{{currentFirstCategory.hasThirdChildren}}">
<view class="category-item" wx:for="{{secondCategory}}" wx:key="*this" wx:for-item="item">
<view class="img-con">
<image data-id="{{secondCategory.id}}"
data-label="{{secondCategory.label}}"
<image
data-id="{{item.id}}"
data-item="{{item}}"
data-label="{{item.label}}"
bindtap="onTapToGoodsList"
src="{{item.image ? item.image : defaultWidthCategoryImg}}" mode="widthFix"></image>
</view>
<view class="more"
data-id="{{secondCategory.id}}"
data-label="{{secondCategory.label}}"
data-id="{{item.id}}"
data-label="{{item.label}}"
bindtap="onTapToGoodsList">
<label>{{item.label}}</label>
<view class="right-more">
......
......@@ -84,14 +84,15 @@ wxService.page({
item.canRefundNum = (item.count - item.refundCount) >= 0 ? (item.count - item.refundCount) : 0;
sum = sum + item.price * item.count;
});
if(data.order.wechatCouponPrice){
data.order.wechatCouponPrice = data.order.wechatCouponPrice/10/10;
data.payAmount = (data.payAmount *1) - (data.order.wechatCouponPrice*1)
}
if(data.order.postCouponDisCount){
data.order.postCouponDisCount = data.order.postCouponDisCount/10/10;
if(data.order){
if (data.order.wechatCouponPrice) {
data.order.wechatCouponPrice = data.order.wechatCouponPrice / 10 / 10;
data.payAmount = (data.payAmount * 1) - (data.order.wechatCouponPrice * 1)
}
if (data.order.postCouponDisCount) {
data.order.postCouponDisCount = data.order.postCouponDisCount / 10 / 10;
}
}
......@@ -300,7 +301,7 @@ wxService.page({
showCancel: true,
cancelText: '取消',
confirmText: '删除',
confirmColor: app.globalData.themeColor,
confirmColor: '#cb3c3c',
success: function (modalRes) {
if (modalRes.confirm) {
const { id } = e.currentTarget.dataset
......@@ -382,7 +383,7 @@ wxService.page({
showCancel: true,
cancelText: '再想想',
confirmText: '取消订单',
confirmColor: app.globalData.themeColor,
confirmColor: '#cb3c3c',
success: function (modalRes) {
if (modalRes.confirm) {
//跳去开卡
......
......@@ -13,7 +13,7 @@
},
"compileType": "miniprogram",
"libVersion": "2.8.2",
"appid": "wxac09792264c49b5c",
"appid": "wxe6d270a3e399ade9",
"projectname": "7.0-%E7%83%AD%E9%A3%8E%E5%BE%AE%E5%95%86%E5%9F%8E",
"debugOptions": {
"hidedInDevtools": []
......@@ -687,6 +687,13 @@
"pathName": "subPackage/page/pages/couponCenterInfo/couponCenterInfo",
"query": "id=708696469342916608",
"scene": null
},
{
"id": 95,
"name": "全渠道-商品详情",
"pathName": "omniChannel/pages/productDetail/productDetail",
"query": "scene=11002054%3aH14W970801235%3a3",
"scene": null
}
]
}
......
// pages/userCenter.js
const wxService = require('../../../../utils/wxService')
const util = require('../../../../utils/util')
wxService.page({
/**
* 页面的初始数据
*/
data: {
query: '',
integralCouponList: [], // 积分兑换优惠券列表
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.hideShareMenu();
this.initIntegralCouponList();
},
// 获取优惠券活动列表
initIntegralCouponList(refresh) {
wx.showLoading({
title: '加载中'
});
wxService.post(`/coupon/couponCenterActivity/buyer/getValidList`).then(res => {
if (res) {
const { result, data } = res.data
if (result == 0) {
wx.hideLoading()
this.data.integralCouponList = data ? data : [];
this.setData({
integralCouponList: this.data.integralCouponList
});
}
}
/**
* 页面的初始数据
*/
data: {
query: '',
integralCouponList: [], // 积分兑换优惠券列表
showDialog: false,
dialogPicture: '',
},
if(refresh){
wx.showToast({
title: '刷新成功',
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.hideShareMenu();
this.initIntegralCouponList();
},
// 获取优惠券活动列表
initIntegralCouponList(refresh) {
wx.showLoading({
title: '加载中'
});
wx.stopPullDownRefresh();
}
}).finally(() => {
wx.hideLoading();
})
},
//立即兑换优惠券
exchange(e) {
wx.showLoading({
title: '领取中..',
});
const { id } = e.currentTarget.dataset;
wxService.post(`/coupon/couponCenterActivity/buyer/coupon/draw?id=${id}`).then(res => {
wx.hideLoading();
if(res){
if(res.data.result == 0){
wx.showToast({
title: '领取成功',
});
wxService.post(`/coupon/couponCenterActivity/buyer/getValidList`).then(res => {
if (res) {
let { result, data } = res.data
if (result == 0) {
wx.hideLoading();
data = data ? data : [];
data.forEach(item => {
//判断活动开始时间是不是已经开始了
item.isStart = true;
//判断是不是老活动
if (item.couponList) {
item.isStart = util.compareCurrentDate(item.startTime);
}
});
this.data.integralCouponList = data;
this.setData({
integralCouponList: this.data.integralCouponList
});
}
}
if (refresh) {
wx.showToast({
title: '刷新成功',
});
wx.stopPullDownRefresh();
}
}).finally(() => {
wx.hideLoading();
})
},
//立即兑换优惠券
exchange(e) {
let isStart = e.currentTarget.dataset.start;
const { id } = e.currentTarget.dataset;
let item = e.currentTarget.dataset.item;
//先判断是不是老的活动
if (!item.couponList) {
wx.showLoading({
title: '领取中..',
});
this.getCoupon(id, item);
return;
}
else{
wx.showToast({
title: '领取失败,请稍后再试',
icon : 'none'
});
if (isStart) {
wx.showLoading({
title: '领取中..',
});
this.getCoupon(id, item);
}
}
});
},
//跳转到详情
goCouponDetail(e) {
const { id } = e.currentTarget.dataset
wxService.router(`/subPackage/page/pages/couponCenterInfo/couponCenterInfo?id=${id}`)
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
this.initIntegralCouponList(true);
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
//预约
else {
if (!item.isAppointMent){
this.orderCouponActivity(id, item);
}
}
},
//立即领取
getCoupon(id, item) {
wxService.post(`/coupon/couponCenterActivity/buyer/coupon/draw?id=${id}`).then(res => {
wx.hideLoading();
if (res) {
if (res.data.result == 0) {
//判断是不是老活动
if (item.couponList) {
this.data.showDialog = true;
this.data.dialogPicture = item.dialogPicture;
this.setData({
showDialog: this.data.showDialog,
dialogPicture: this.data.dialogPicture
});
}
else {
wx.showToast({
title: '领取成功!',
});
}
}
else {
wx.showToast({
title: '领取失败,请稍后再试',
icon: 'none'
});
}
}
});
},
//立即预约
orderCouponActivity(id) {
let self = this;
let baseUserInfo = wx.getStorageSync('_baseUserInfo');
wxService.post(`${'/merchant/message/wxSubMsgMapping/getListByParams'}`, {
scenarioIds: ['usernoticeappointment'],
sourceFrom: 2,
switchType: 3
}).then(res => {
let tempArr = res.data.data ? res.data.data : [];
if (tempArr.length == 0) {
return;
}
let tempids = [];
tempArr.map(item => {
tempids.push(item.templateId);
});
wx.requestSubscribeMessage({
tmplIds: tempids,
success: (res) => {
for (let i = 0; i < tempArr.length; i++) {
wxService.post(`${'/merchant/message/wxSubMsgSubscride/member/subscribe'}`, {
businessId: id,
memberId: baseUserInfo.memberId,
scenarioId: tempArr[i].scenarioId,
templateId: tempArr[i].templateId
}).then(resp => { });
}
},
complete: (res) => {
wx.showLoading({
title: '加载中',
})
setTimeout(()=>{
self.initIntegralCouponList();
wx.hideLoading();
},1000)
}
})
}).catch(err => {
})
},
//跳转到详情
goCouponDetail(e) {
const { id } = e.currentTarget.dataset
wxService.router(`/subPackage/page/pages/couponCenterInfo/couponCenterInfo?id=${id}`)
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
this.initIntegralCouponList(true);
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
})
\ No newline at end of file
......@@ -17,6 +17,7 @@
<image wx:if="{{item.listPicture}}" src='{{item.listPicture}}' mode="aspectFit"/>
<image wx:else src='https://img3.bigaka.com/prd/3001/202003/20200331/3001649f2f08-3b4e-4b5b-97c1-30cdf646651c.png' />
</view>
<!-- <view class='ac-date'>{{item.startTime}}至{{item.endTime}}</view> -->
<view class='coupon-info'>
<view class='coupon-name fs-28'>{{item.activityName}}</view>
<view class='coupon-desc text-align-left fs-24'>查看详情</view>
......@@ -29,8 +30,9 @@
class="clear-btn positionAbs"></button>
<view class='coupon-btn-click theme-color'
data-id="{{item.acvivityId}}"
bindtap='exchange'>立即领取</view>
<!-- <view class='ac-date'>{{item.startTime}}至{{item.endTime}}</view> -->
data-start="{{item.isStart}}"
data-item="{{item}}"
bindtap='exchange'>{{item.isStart ? '立即领取': (item.isAppointMent?'已预约':'立即预约')}}</view>
</view>
</view>
</view>
......@@ -48,7 +50,8 @@
<go-guid />
<go-home/>
<floatNav bind:getAuth="_getUserInfo" bind:updatePage="updatePage"/>
<!-- image-dialog -->
<image-dialog showDialog="{{showDialog}}" imageUrl="{{dialogPicture}}"></image-dialog>
......@@ -133,9 +133,13 @@ wxService.page({
if (tempids.length > 0) {
let status = res[tempids[0]];
if (status == 'accept') {
this.getACtivityInfo();
wx.showToast({
title: '预约成功',
this.data.activityInfo.isAppointMent = true;
this.setData({
activityInfo: this.data.activityInfo
},()=>{
wx.showToast({
title: '预约成功',
})
})
}
}
......
......@@ -41,7 +41,7 @@ class='card-info' mode='widthFix'></image>
<view class='rg-button positionRe {{checked ? "" : "disabled"}}' wx:if="{{!userHasBaseInfo}}">
<button class="positionAbs clear-btn"
bindgetuserinfo="_getUserInfo" open-type='getUserInfo'></button>
{{buyType == 1 ? "立即购买" : "立即兑换"}}
立即购买
</view>
<view class='rg-button {{checked ? "" : "disabled"}}'
wx:if="{{userHasBaseInfo}}" bindtap='onTapBuy'>立即购买</view>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment