dingdong-mall/pages/product/product-detail.vue

600 lines
21 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<page-meta :page-style="'overflow:'+(ifShowPageMeta?'hidden':'visible')"></page-meta>
<view>
<!-- 顶部操作条 -->
<cu-custom :bgColor="'bg-white'" :isBack="true" :isBackHome="false" :homePageUrl="'/pages/index/index'">
<block slot="backText">返回</block>
<!-- <block slot="backHomeText">首页</block> -->
<block slot="content">商品详情</block>
</cu-custom>
<!-- 导航栏 -->
<uni-transition class="fixed-top-bar" mode-class="fade" :show="showTopNav">
<view class="grid text-center col-2 solid-top solid-bottom bg-white">
<view class="padding" :class="curTopNav == 0 ? 'bg-blue' : ''" @click.stop="clickNav(0)">服务</view>
<!-- <view class="padding" :class="curTopNav == 1 ? 'bg-blue' : ''" @click.stop="clickNav(1)">评价</view> -->
<view class="padding" :class="curTopNav == 2 ? 'bg-blue' : ''" @click.stop="clickNav(2)">详情</view>
</view>
</uni-transition>
<!-- 轮播图视频 :autoplay="!productVideoPlaying" interval="5000" duration="500"-->
<swiper :class="changeSwiperHeight ? 'sm-screen-swiper' : 'sm-screen-swiper lg-screen-swiper'" @change="changeSwiper">
<swiper-item v-if="productDetail.goodsVideoUrl">
<video style="width: 100%; height: 100%;" id="productVideo" :src="productDetail.goodsVideoUrl" :controls="true" :autoplay="false"
:show-center-play-btn="true" :show-fullscreen-btn="true"></video>
</swiper-item>
<swiper-item v-for="(item,index) in swiperList" :key="item.goodsImgsId" @click="clickSwiper($event, item, 1)">
<image style="width: 100%; height: 100%;" :src="item.imgUrl" mode="aspectFit"></image>
</swiper-item>
</swiper>
<!-- 价格及活动栏 -->
<view class="bg-gradual-color padding-sm margin-bottom-xs shadow-blur">
<view class="flex justify-between align-center">
<view v-if="curProductSpecs.discountPrice">
<text class="text-sl text-price">{{curProductSpecs.discountPrice}}</text>
<text class="text-del">
<text class="text-xxl">¥{{curProductSpecs.goodsPrice}}</text>
</text>
<text class="margin-left-xs text-xxl">/{{curProductSpecs.goodsUnit}}</text>
</view>
<view v-else>
<text class="text-sl text-price">{{curProductSpecs.goodsPrice}}</text>
<text class="margin-left-xs text-xxl">/{{curProductSpecs.goodsUnit}}</text>
</view>
<view>
<text class="text-df">已售:{{curProductSpecs.saleNum}}</text>
</view>
</view>
<view id="pageAnchor0" class="flex justify-between align-end">
<view class="text-df" v-if="curUserInfo.placeStatus === 2">
佣金:<text class="text-price margin-right-sm">{{curProductSpecs.finalPrice ? curProductSpecs.finalPrice : 0}}</text>
<!-- <text class="cuIcon-share"></text> -->
</view>
<!-- <view class="text-df">
距结束:<uni-countdown style="float: right;" :day="1" :hour="1" :minute="12" :second="40" background-color="#fff" splitorColor="#fff"></uni-countdown>
</view> -->
<view class="flex justify-end text-df align-center">
<!-- <view>距结束:</view> -->
<!-- <uni-countdown style="float: right;" :day="1" :hour="1" :minute="12" :second="40"
background-color="#fff" splitorColor="#fff"></uni-countdown> -->
</view>
</view>
</view>
<!-- 产品概要 -->
<view class="bg-white padding-sm">
<view class="flex justify-between text-df align-center">
<view class="padding-right-sm text-left">
<view class="text-xl">
<view class='cu-tag round bg-orange light' v-if="productDetail.servActivity">
<text>{{productDetail.servActivity}}</text>
</view>
<view class='cu-tag round light bg-blue padding-lr-sm' v-if="productDetail.deptGoodsCategoryName">
<text v-if="productDetail.parGoodsCategoryName">
{{productDetail.parGoodsCategoryName}}
<text class="margin-lr-xs">/</text>
</text>
<text>{{productDetail.deptGoodsCategoryName}}</text>
</view>
{{productDetail.goodsName}}
</view>
<view class="text-sm text-gray margin-top-xs">{{productDetail.goodsDesc}}</view>
</view>
<view class="text-xl text-right padding-lr solid-left">
<!-- <view class="margin-tb-xs"><text class="cuIcon-share"></text></view> -->
<view v-if="productInfo.isGoldServ" class="margin-tb-xs text-orange"><text
class="cuIcon-friendfamous"></text></view>
</view>
</view>
</view>
<!-- 服务保障和规格 -->
<view class="margin-lr-sm padding margin-top-sm bg-white">
<view v-if="productDetail.expectDuration">
<view class="cu-capsule margin-tb-xs">
<view class='cu-tag bg-main-color'>
<text class="cuIcon-repairfill"></text>
</view>
<view class="cu-tag line-main-color">
服务时效
</view>
</view>
<text class="margin-lr-xs text-sm">{{productDetail.expectDuration}}</text>
</view>
<view v-if="productDetail.warrantyPeriod">
<view class="cu-capsule margin-tb-xs">
<view class='cu-tag bg-main-color'>
<text class="cuIcon-repairfill"></text>
</view>
<view class="cu-tag line-main-color">
服务保障
</view>
</view>
<text class="margin-lr-xs text-sm">质保期{{productDetail.warrantyPeriod}}&nbsp&nbsp不满意重新服务&nbsp&nbsp快速退赔</text>
</view>
<view>
<view class="cu-capsule margin-tb-xs">
<view class='cu-tag bg-main-color'>
<text class="cuIcon-deliver_fill"></text>
</view>
<view class="cu-tag line-main-color">
服务区域
</view>
</view>
<text v-for="(item,index) in productDetail.goodsAreaList">
<text class="margin-lr-xs text-sm">{{item.areaName}}<text v-if="index != productDetail.goodsAreaList.length - 1">,</text></text>
</text>
</view>
<view>
<view class="cu-capsule margin-tb-xs">
<view class='cu-tag bg-main-color'>
<text class="cuIcon-deliver_fill"></text>
</view>
<view class="cu-tag line-main-color">
区域备注
</view>
</view>
<text class="margin-lr-xs text-sm">{{productDetail.areaDesc}}</text>
</view>
<view>
<view class="cu-capsule margin-tb-xs">
<view class='cu-tag bg-red'>
<text class="cuIcon-noticefill"></text>
</view>
<view class="cu-tag line-red">
请核对下单地址与服务区域相匹配
</view>
</view>
</view>
<!-- <view v-if="productDetail.remark">
<view class="cu-capsule margin-tb-xs">
<view class='cu-tag bg-main-color'>
<text class="cuIcon-commentfill"></text>
</view>
<view class="cu-tag line-main-color">
备注
</view>
</view>
<text class="margin-lr-xs text-sm">{{productDetail.remark}}</text>
</view> -->
<view class="solid-top text-lg padding-tb-sm">
<view class='cu-tag light radius bg-orange padding-lr-xs' style="font-size: 0.9rem;" v-if="productDetail.deptGoodsCategoryName">
<text v-if="productDetail.parGoodsCategoryName">
{{productDetail.parGoodsCategoryName}}
<text>/</text>
</text>
<text>{{productDetail.deptGoodsCategoryName}}</text>
</view>
<text class="text-black margin-left-sm" style="vertical-align: middle;">查看产品</text>
</view>
<view class="flex flex-wrap" :class="isShowAllSpecs ? '' : 'certern-height'">
<view class="margin-tb-xs margin-right-xs" v-for="(item,index) in productDetail.goodsStandardList" :key="item.goodsStandardId">
<view class='cu-tag round padding'
:class="curProductSpecs.goodsStandardId === item.goodsStandardId ? 'line-main-color' : 'line-default'"
@click="chooseSpecs(item)">{{item.goodsStandardName}}</view>
</view>
</view>
<view class="text-bold text-gray text-lg text-center bg-white padding-top-sm" @click="showAllSpecs()"><text v-if="!isShowAllSpecs">展开</text><text
:class="'cuIcon-' + (isShowAllSpecs ? 'fold' : 'unfold')"></text></view>
</view>
<!-- 服务评价 -->
<!-- <view id="pageAnchor1" class="margin-lr-sm margin-top-sm bg-white"> -->
<!-- <view class="flex justify-between align-end padding"> -->
<!-- <view class="text-black text-lg">商品评价</view> -->
<!-- <view class="text-red text-sm">好评率95%<text class="text-bold text-gray cuIcon-right"></text></view> -->
<!-- </view> -->
<!-- <view class="text-center padding-bottom">开发中,敬请期待</view> -->
<!-- <comments-card :reviewers="reviewers"></comments-card> -->
<!-- </view> -->
<!-- 店家链接 -->
<view class="margin-lr-sm margin-top-sm padding bg-white">
<view class="flex justify-between align-center">
<view class="flex justify-start align-center">
<view class="cu-avatar round" :style="'background-image:url(' + defaultHead(shopInfo.workerLogoUrl) + ');'"></view>
<view class="content flex-sub margin-lr-sm">
<view class="text-black">{{shopInfo.name}}</view>
<uni-rate :size="15" :readonly="true" allow-half :value="5" />
</view>
</view>
<view class="text-sm" @click="showShopDetail(shopInfo)">店铺查看<text class="text-bold text-gray cuIcon-right"></text></view>
</view>
</view>
<!-- 服务详情 -->
<view id="pageAnchor2" class="margin-lr-sm margin-top-sm bg-white margin-bottom-with-bar ">
<view class="text-center padding-xl">{{productDetail.remark}}</view>
<view class="image">
<image v-for="(item,index) in detailPicList" :key="index" :src="item.imgUrl" mode="widthFix" style="width: 100%;"></image>
</view>
</view>
<!-- 底部操作条 -->
<view class="cu-bar bg-white tabbar border shop fixed-bottom-bar" style="flex-direction: row;">
<view class="action" @click="showIndex">
<view class="cuIcon-homefill"></view>
首页
</view>
<button class="action" open-type="contact">
<view class="cuIcon-servicefill text-green">
<!-- <view class="cu-tag badge" v-if="ifHasCsMsg"></view> -->
</view>
客服
</button>
<view class="action" @click="showShopDetail(shopInfo)">
<view class="cuIcon-taoxiaopu text-orange"></view>
店铺
</view>
<!-- <view class="action">
<view class=" cuIcon-shop"></view> 店铺
</view> -->
<!-- <view class="action" @click="showCart">
<view class="cuIcon-cart">
<view class="cu-tag badge" v-if="totalPickCount > 0">{{totalPickCount}}</view>
</view>
购物车
</view> -->
<!-- <view class="bg-main-color light submit" @click="toggleProductPickModal">加入购物车</view> -->
<view class="bg-main-color submit" @tap="checkLogin" @click="beforeCheckStatusThenOpen">立即订购</view>
</view>
<!-- 底部弹窗 -->
<uni-popup ref="productPickPopup" type="bottom" @change="changePopupState">
<view class="text-bold text-gray text-lg text-center left-top-sm-bar" @click="toggleProductPickModal"><text
class="cuIcon-close"></text></view>
<product-pick :shopInfo="shopInfo" :productInfo="productDetail" :specsList="productDetail.goodsStandardList" :orderNow="orderNow"></product-pick>
</uni-popup>
<!-- 登录校验弹窗 -->
<vertify-login ref="vertifyLogin" @reload="checkLogin"></vertify-login>
<vertify-phone ref="vertifyPhone" @reload="checkLogin"></vertify-phone>
</view>
</template>
<script>
import commentsCard from '@/components/goods-card/comments-card.vue';
import productPick from '@/pages/product/product-pick.vue';
export default {
components: {
commentsCard,
productPick
},
data() {
return {
inParam: {},
productDetail: {},
detailPicList: [],
swiperList: [],
curProductSpecs: {},
productInfo: {},
guaranteeList: [],
isShowAllSpecs: false,
reviewers: [],
productVideoPlaying: false,
showTopNav: false,
changeSwiperHeight: false,
curTopNav: 0,
shopInfo: {},
ifShowPageMeta: false,
orderNow: false,
totalPickCount: 0,
ifHasCsMsg: true,
picUrls: [],
curUserInfo: {},
defaultAddress: null
}
},
onLoad(options) {
let params = JSON.parse(decodeURIComponent(options.params));
this.inParam = params;
this.loadData();
this.bindEvent();
this.loadDefaultAddress()
},
onUnload() {
this.offBindEvent();
},
onReady() {
this.productVideoContext = uni.createVideoContext('productVideo');
},
onPageScroll(e) {
this.showTopNav = e.scrollTop > 250 ? true : false;
this.changeSwiperHeight = e.scrollTop > 50 ? true: false;
},
onShareAppMessage(e) {
let params = {
goodsId: this.inParam.goodsId,
distributor: this.curUserInfo.customerId
}
return {
title: this.productDetail.goodsName,
path: '/pages/product/product-detail?params=' + encodeURIComponent(JSON.stringify(params)),
// imageUrl: productDetail
}
},
onShareTimeline(e) {
let params = {
goodsId: this.inParam.goodsId,
distributor: this.curUserInfo.customerId
}
return {
title: this.productDetail.goodsName,
path: '/pages/product/product-detail?params=' + encodeURIComponent(JSON.stringify(params)),
imageUrl: this.productDetail.goodsImgUrl
}
},
methods: {
async loadData() {
await this.$request.refreshCurUserCache();
this.curUserInfo = this.$request.getCurUserInfo();
if(this.curUserInfo) {
let productDetailMock = await this.$api.data('productDetail');
this.productDetail = await this.$request.getGoodsDetail({
goodsId: this.inParam.goodsId
});
// 默认规格
this.curProductSpecs = this.productDetail.goodsStandardList[0];
// 轮播图
this.swiperList = this.productDetail.goodsImgsMap["0"];
// 详情图
this.detailPicList = this.productDetail.goodsImgsMap["1"];
// 用于点击放大查看图片
this.swiperList.forEach((picItem) => {
this.picUrls.push(picItem.imgUrl);
})
this.detailPicList.forEach((picItem) => {
this.picUrls.push(picItem.imgUrl);
})
let res = await this.$request.getWorkerAllDetailById({
workerId: this.productDetail.workerId
})
this.shopInfo = res.data;
this.guaranteeList = productDetailMock.guaranteeList;
this.productInfo = productDetailMock.productInfo;
this.reviewers = productDetailMock.reviewers;
// this.shopInfo = productDetailMock.shopInfo;
if(this.inParam.distributor) {
await this.$request.updateUser({
customerPlace: this.inParam.distributor,
customerId: this.curUserInfo.customerId
});
}
}
},
async checkLogin() {
let loginRes = await this.authLogin();
if (!loginRes) {
return;
}
this.loadData();
},
async authLogin() {
// 更新缓存中的userInfo
let res = await this.$request.storageExistUser();
// 获取缓存中的userInfo
let curUserInfo = this.$request.getCurUserInfo();
// 校验提示登录
if (!curUserInfo || !curUserInfo.openId) {
this.$refs.vertifyLogin.showModal();
return false;
} else {
this.$refs.vertifyLogin.hideModal();
}
// 校验提示获取手机号码
if (!curUserInfo.phone) {
this.$refs.vertifyPhone.showModal();
return false;
} else {
this.$refs.vertifyPhone.hideModal();
}
return true;
},
bindEvent() {
uni.$on('product-detail_add2Cart', this.add2Cart);
},
offBindEvent() {
uni.$off('product-detail_add2Cart');
},
chooseSpecs(item) {
this.curProductSpecs = item;
},
showAllSpecs() {
this.isShowAllSpecs = !this.isShowAllSpecs;
},
clickSwiper(e, item, type) {
if (type === 1) {
this.viewImage(item.imgUrl);
} else if (type === 0) {
this.pauseVideo(e);
}
},
viewImage(url) {
uni.previewImage({
urls: this.picUrls,
current: url
});
},
pauseVideo(e) {
if (this.productVideoPlaying) {
this.productVideoContext.exitFullScreen();
this.productVideoContext.pause();
} else {
this.productVideoContext.requestFullScreen();
this.productVideoContext.play();
}
this.productVideoPlaying = !this.productVideoPlaying;
},
changeSwiper(e) {
// 只有第一个是视频,如果是切换到图片就停止播放
if (e.detail.current !== 0) {
this.productVideoContext.pause();
this.productVideoPlaying = false;
}
},
clickNav(index) {
// 修改聚焦时的样式
this.curTopNav = index;
// 跳转到指定目录
uni.pageScrollTo({
selector: '#pageAnchor' + index
})
},
async loadDefaultAddress() {
let res = await this.$request.getAddressList({
customerId: this.$request.getCurUserInfo().customerId,
isDefault: 1
});
if (res && res.data &&res.data.length) {
const defaultAdd = res.data.filter(i => i.isDefault === 1)
this.defaultAddress = defaultAdd.length ? defaultAdd[0] : res.data[0];
}
},
// 检测当前默认地址是否在服务区域之间
checkDefaultAddressIfInclude() {
return new Promise((resolve, reject) => {
const allAreaId = this.productDetail.goodsAreaList.map(i => i.countryAreaId)
const status = allAreaId.includes(this.defaultAddress.countryId)
console.log('checkDefaultAddressIfInclude == ', status)
if(!status) {
uni.showModal({
title: '提示',
content: '产品页面的【服务区域】与您默认的地址不匹配,如未选错产品,请提交后改新地址!',
cancelText: '返回查看',
confirmText: '继续下单',
success: res => {
if (res.confirm) {
resolve(true)
} else {
resolve(false)
}
}
})
} else {
resolve(true)
}
})
},
async checkCurAreaIncludeServiceAreas() {
return new Promise((resolve, reject) => {
let curLocation = uni.getStorageSync('curLocation');
if(!curLocation) resolve(true)
const curAreaId = curLocation.area[curLocation.area.length - 1].areaId
const allAreaId = this.productDetail.goodsAreaList.map(i => i.countryAreaId)
if(!allAreaId.includes(curAreaId)) {
uni.showModal({
title: '提示',
content: '所选产品与您目前所在位置定位不是同一个区/县,请查看产品页面的【服务区域】与【区域备注】!',
cancelText: '返回查看',
confirmText: '继续下单',
success: res => {
if (res.confirm) {
resolve(true)
} else {
resolve(false)
}
}
})
} else {
resolve(true)
}
})
},
async beforeCheckStatusThenOpen() {
if(this.defaultAddress) {
const status = await this.checkDefaultAddressIfInclude()
if(status) {
this.toggleProductPickModal(null, true)
}
} else {
const areaStatus = await this.checkCurAreaIncludeServiceAreas()
if(areaStatus) {
this.toggleProductPickModal(null, true)
}
}
// console.log('checkDefaultAddressIfInclude == start',)
// const status = await this.checkDefaultAddressIfInclude()
// console.log('checkDefaultAddressIfInclude == ', status)
// if(status) {
// const areaStatus = await this.checkCurAreaIncludeServiceAreas()
// if(areaStatus) {
// this.toggleProductPickModal(null, true)
// }
// }
// if(!status) {
// uni.showModal({
// title: '提示',
// content: '所选产品与您目前所在位置定位不是同一个区/县,请查看产品页面的【服务区域】与【区域备注】!',
// cancelText: '返回查看',
// confirmText: '继续下单',
// success: res => {
// if (res.confirm) {
// this.toggleProductPickModal(null, true)
// }
// }
// })
// } else {
// this.toggleProductPickModal(null, true)
// }
},
async toggleProductPickModal(e, orderNow) {
this.orderNow = orderNow ? true : false;
if (this.ifShowPageMeta) {
this.$refs.productPickPopup.close();
} else {
this.$refs.productPickPopup.open();
}
},
changePopupState(e) {
this.ifShowPageMeta = e.show;
},
add2Cart(totalPickCount) {
this.totalPickCount = totalPickCount;
this.toggleProductPickModal();
},
showShopDetail(shopInfo) {
uni.navigateTo({
url: '../product/shop-detail?shopInfo=' + encodeURIComponent(JSON.stringify(shopInfo))
});
},
showCart() {
let myCartInfo = {};
uni.navigateTo({
url: '/pages/my/my-cart?myCartInfo=' + encodeURIComponent(JSON.stringify(myCartInfo))
});
},
showIndex() {
uni.reLaunch({
url: '/pages/index/home'
});
},
defaultHead(url) {
if(url === 'https://thirdwx.qlogo.cn/mmopen/vi_32/POgEwh4mIHO4nibH0KlMECNjjGxQUq24ZEaGT4poC6icRiccVGKSyXwibcPq4BWmiaIGuG1icwxaQX6grC9VemZoJ8rg/132') {
return 'http://gqz.opsoul.com/2741722238771_.pic.jpg'
}
return url
}
}
}
</script>
<style scoped>
.certern-height {
max-height: 300rpx;
overflow: hidden;
}
.left-top-sm-bar {
position: absolute;
right: 25rpx;
top: 25rpx;
z-index: 99;
}
.sm-screen-swiper {
height: 400rpx;
transition: all 0.5s ease-in-out;
}
.lg-screen-swiper {
height: 115vw;
transition: all 0.5s ease-in-out;
}
</style>