时空网前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

884 lines
22 KiB

<template>
<view>
<skeleton :loading="skeletonLoading" :row="12" :showAvatar="false" :showTitle="true">
<block v-if="isRight(goods_detail)">
<!-- 商品图片轮播 -->
<swiper :current="current" :indicator-dots="goods_detail.banners.length > 1 ? true : false"
:circular="true" class="swiper-box" indicator-active-color="#FE9903">
<swiper-item v-for="(item, index) in goods_detail.banners" :key="item.id">
<image mode="aspectFill" :src="item.cover" style="width: 100%; height: 100%;"
@click="lookImg(index)"></image>
</swiper-item>
</swiper>
<view class="bill-position" @tap='formSubmit()' v-if="isShowButtonCount >= 2">
<button class="cu-btn1 margin-left-sm lf-font-28 lf-m-20">
分享海报
</button>
</view>
<!-- 商品主要信息 -->
<view class="head-info">
<view class="lf-font-40">{{ goods_detail.name }}</view>
<view class="lf-row-between lf-font-24 lf-m-t-30 lf-p-b-20">
<view class="lf-flex price">
<lf-price :price="goods_detail.specs[0].selling_price"></lf-price>
<view class="lf-m-l-20">¥{{ goods_detail.specs[0].original_price }}</view>
<view v-if="goods_detail.specs[0].cost">{{ goods_detail.specs[0].cost }}</view>
</view>
<view class="lf-font-24 lf-text-right">
<view class="lf-color-gray">{{ goods_detail.specs[0].sold_stock_text }}</view>
<view class="lf-color-primary" v-if="goods_detail.specs[0].stock && goods_detail.specs[0].stock < 100">{{ goods_detail.specs[0].stock_text }}</view>
</view>
</view>
<view class="label-box" v-if="goods_detail.tags && goods_detail.tags.length">
<view class="label-item" v-for="(item, index) in goods_detail.tags" :key="index">{{ item }}
</view>
</view>
</view>
<!-- 地址信息 -->
<view class="address-box">
<view class="lf-font-32 lf-font-bold">适用门店</view>
<view class="lf-m-t-20 lf-row-between">
<view class="lf-flex">
<image mode="aspectFill" class="lf-fle shop-img" :src="goods_detail.store.cover"
v-if="goods_detail.store.cover"></image>
<image mode="aspectFill" class="lf-fle shop-img" src="../../static/center/shop-logo.png"
v-else></image>
<view class="lf-font-32 lf-m-l-20 lf-line-1" style="max-width: 512rpx;">
{{ goods_detail.store.name }}</view>
</view>
<view @click="makePhoneCall(goods_detail.store.tel)">
<text class="lf-iconfont lf-icon-dianhua lf-font-40" style="color: #3A62FF;"></text>
</view>
</view>
<view class="lf-flex lf-m-t-20" @click="openMap">
<view style="width: 60rpx; height: 60rpx;" class="lf-row-center">
<text class="lf-iconfont lf-icon-dizhi lf-font-40" style="color: #555555;"></text>
</view>
<view class="lf-m-l-20 lf-font-28" style="color: #555555;">{{ goods_detail.store.address }}
</view>
</view>
</view>
<!-- 商品详情 -->
<view class="goods-detail">
<view class="lf-font-32 lf-font-bold lf-m-b-20">商品详情</view>
<rich-text :nodes="afterDone"
v-if="goods_detail.content_type == 'rich_text'"></rich-text>
<image class="goods-img" :src="item" v-for="(item, index) in goods_detail.content" :key="index"
v-if="goods_detail.content_type == 'img'"></image>
</view>
<!-- 修饰专用 -->
<view class="extra"></view>
<!-- 吸底操作按钮 -->
<view class="lf-row-between fixed-bottom">
<view class="lf-flex lf-p-t-10 lf-p-b-10">
<view class="lf-flex-column lf-row-center icon-item"
@click="$url('/pages/index/index', {type: 'switch'})">
<image class="icon-img" src="../../static/center/home.png"></image>
<view class="lf-m-t-1">首页</view>
</view>
<view class="lf-flex-column lf-row-center icon-item"
@click="$url('/pages/contactService/index')">
<image class="icon-img" src="../../static/center/service.png"></image>
<view class="lf-m-t-1">客服</view>
</view>
<view class="lf-flex-column lf-row-center icon-item" @click="switchCollect">
<image class="icon-img" src="../../static/center/collect-active.png" v-if="is_collect">
</image>
<image class="icon-img" src="../../static/center/collect.png" v-else></image>
<view class="lf-m-t-1">{{ is_collect ? '已收藏' : '收藏' }}</view>
</view>
<button class="lf-flex-column lf-row-center icon-item" open-type="share">
<image class="icon-img" src="../../static/center/share.png"></image>
<view class="lf-m-t-1">分享</view>
</button>
</view>
<button class="btn" @click="toAddOrder">立即抢购</button>
</view>
<!-- 回到顶部 -->
<!-- <u-back-top :scroll-top="pageScrollTop" :custom-style="{background: 'rgba(51, 51 51, 0.3)'}" :icon-style="{color: '#ffffff'}"></u-back-top> -->
<u-back-top :scroll-top="pageScrollTop" :custom-style="{background: 'rgba(51, 51 51, 0.3)'}">
</u-back-top>
</block>
</skeleton>
<view class="canvas-box">
<canvas style="width: 375px;height: 667px;position:fixed;top:9999px" canvas-id="mycanvas" />
</view>
<view class='imagePathBox' v-if="maskHidden == true && imagePath" @click="maskHidden = false ">
<image :src="imagePath" class='shengcheng' mode="widthFix"></image>
<button class='baocun' @click.stop="saveBill()">保存相册,分享到朋友圈</button>
</view>
</view>
</template>
<script>
let SparkMD5 = require("@/common/SparkMD5.js"); // 签名加密js文件
export default {
data() {
return {
current: 0, // 轮播下标
goods_id: 0,
goods_detail: {},
is_collect: 0, // 1为当前收藏商品了,0为否
skeletonLoading: true,
base64Img: '',
checkArea: 'Cannot find module',
maskHidden: false,
info: {
avatar: '',
nickname: '',
id: '',
tel: '',
tags: []
},
showLogin: true,
imagePath: '',
userToken: '',
wxCode: '',
onceCode: '',
pt: 1,
afterDone: '',
backgroundImg: '',
goodShare: '',
s_id: '',
isShowButtonCount: 0,
userInfo: {}
}
},
computed: {
isRight() {
return function(val) {
return this.$shared.isRight(val);
}
}
},
onLoad(options) {
this.goods_id = options.id;
this.pt = options.pt || 1;
this.s_id = options.share_id || '';
this.userInfo = uni.getStorageSync('userinfo') || {};
this.getGoodsDetail();
this.getWxCode()
this.getBackground()
},
methods: {
getBackground() {
let _this = this
_this.$http(_this.API.API_BILLBACKGROUND, {
type: 'goods'
}).then(res => {
let img = res.data.img_url
if (img) {
wx.getImageInfo({
src: img,
success: function(sres) {
_this.backgroundImg = sres.path;
_this.isShowButtonCount++;
}
})
}
})
},
//获取商品分享图
getGoodsBackground() {
let _this = this
let goods = _this.goods_detail;
let imageUrl = goods.share_cover || goods.cover;
wx.getImageInfo({
src: imageUrl,
success: function(sres) {
_this.goodShare = sres.path
console.log('商品分享图',_this.goodShare)
}
})
console.log('商品分享图',_this.goodShare)
},
//商品绑定
bindGoods() {
var _this = this;
let yy = new Date().getFullYear();
let mm = new Date().getMonth()+1;
let dd = new Date().getDate();
let hh = new Date().getHours();
let mf = new Date().getMinutes()<10 ? '0'+new Date().getMinutes() : new Date().getMinutes();
let ss = new Date().getSeconds()<10 ? '0'+new Date().getSeconds() : new Date().getSeconds();
let gettime = yy+'-'+mm+'-'+dd+' '+hh+':'+mf+':'+ss;
let userInfo = uni.getStorageSync('userinfo') || {};
let timeDate = Math.round(new Date().getTime() / 1000).toString();
console.log(SparkMD5)
let md5TimeDate = SparkMD5.hash(timeDate)
let nowTime = new Date().toLocaleString();
_this.$http(_this.API.API_BINDGOODS, {
deed: md5TimeDate,
sid: _this.s_id,
gid: _this.goods_id,
gn: _this.goods_detail.name,
t: gettime
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
},
getWxCode() {
const token = this.$shared.createToken({
user_id: this.userInfo.id,
goods_id: this.goods_id
});
let options = {
route: 'goods',
pt: 2,
id: this.goods_id,
share_id: this.userInfo.id,
scene_code: this.$scene.V2_GOODS_SHAREPOSTER
}
this.generateKooken(token, options); // 谁分享了就生成一个token
this.$http(this.API.API_WXBILL, {
scene: token,
page: 'pages/route/index',
width: '2800'
}).then(res => {
this.wxCode = res.data.base_url
if (this.wxCode) {
this.getwxCodeImg()
}
})
},
//海报开始
//保存头像
getwxCodeImg() {
var imgSrc = this.wxCode; //base64编码
var save = wx.getFileSystemManager();
var number = Math.random();
save.writeFile({
filePath: wx.env.USER_DATA_PATH + '/pic' + number + '.jpg',
data: imgSrc,
encoding: 'base64',
success: res => {
this.onceCode = wx.env.USER_DATA_PATH + '/pic' + number + '.jpg';
this.isShowButtonCount++;
console.log('二维码临时路径',this.onceCode)
},
fail: err => {
console.log(err)
}
})
},
createNewImg() {
var that = this;
var context = wx.createCanvasContext('mycanvas');
let goods = that.goods_detail;
let title = goods.name;
let price = '¥'+goods.specs[0].selling_price;
//背景图
var path = that.backgroundImg;
// context.setFillStyle("#fff")
// context.fillRect(0, 0, 375, 600)
let goodsBackground = that.goodShare
context.drawImage(path, 0, 0, 375, 496);
context.drawImage(goodsBackground, 10, 10, 355, 300);
//绘制二维码
let wxcode = that.onceCode
context.drawImage(wxcode, 244, 324, 120, 120);
let message = '长按识别小程序码'
context.setFontSize(16);
context.setFillStyle('#999');
context.setTextAlign('center');
context.fillText(message,300,470);
//绘制价格
context.setFontSize(40);
context.setFillStyle('#FF0000');
context.setTextAlign('center');
context.fillText(price,65, 366);
if(title.length <= 11){
context.setFontSize(20);
context.setFillStyle('#222');
context.setTextAlign('left');
context.fillText(title, 10, 470);
}else{
let str = title;
if(str.length > 22){
str = str.substr(0, 21) + '...';
}
let before = str.substr(0, 11);
let last = str.substr(11, str.length);
context.setFontSize(20);
context.setFillStyle('#222');
context.setTextAlign('left');
context.fillText(before, 10, 448);
context.fillText(last, 10, 472);
}
/*
console.log('标题长度',title.length)
if(title.length < 18 ) {
context.fillText(title, 10, 350);
}else if(18<title.length && title.length<36) {
console.log('1111')
let before = title.substr(0,18)
let last = title.substr(18,title.length)
//绘制标题
context.setFontSize(20);
context.setFillStyle('#222');
context.setTextAlign('left');
context.fillText(before, 10, 350);
context.fillText(last, 10, 374);
}else if(title.length > 36) {
console.log('22222')
console.log(title.substr(18,41))
let before = title.substr(0,18)
let last = title.substr(18,28)
// let last1 = title.substr(36,title.length)
//绘制标题
context.setFontSize(20);
context.setFillStyle('#222');
context.setTextAlign('left');
context.fillText(before, 10, 350);
context.fillText(last, 10, 374);
// context.fillText(last1, 10, 398);
}
*/
context.stroke();
context.draw();
//将生成好的图片保存到本地,需要延迟一会,绘制期间耗时
setTimeout(function() {
wx.hideToast();
wx.canvasToTempFilePath({
canvasId: 'mycanvas',
success: function(res) {
that.imagePath = res.tempFilePath;
if (that.imagePath) {
that.canvasHidden = true
that.maskHidden = true
}
console.log('海报生成成功')
console.log(res)
console.log('图片链接', that.imagePath)
},
fail: function(res) {
console.log(res);
}
});
}, 200);
},
saveBill() {
var that = this
wx.saveImageToPhotosAlbum({
filePath: that.imagePath,
success(res) {
wx.showModal({
content: '图片已保存到相册,赶紧晒一下吧~',
showCancel: false,
confirmText: '好的',
confirmColor: '#333',
success: function(res) {
if (res.confirm) {
console.log('用户点击确定');
that.maskHidden = false
}
},
fail: function(res) {
that.maskHidden = false
}
})
}
})
},
formSubmit() {
var that = this;
that.$u.throttle(() => {
wx.showToast({
title: '生成海报中...',
icon: 'loading',
duration: 1000
});
console.log(that.onceCode)
console.log(that.backgroundImg)
if(that.onceCode && that.backgroundImg) {
that.createNewImg()
}else if(!that.onceCode){
this.$msg('小程序码生成失败!')
}else if(!that.backgroundImg){
this.$msg('海报背景图生成失败!')
}
}, 500);
},
//海报结束
getGoodsDetail() {
let that = this;
this.$http(this.API.API_GOODS_DETAIL, {
goods_id: this.goods_id
}).then(res => {
this.skeletonLoading = false;
this.goods_detail = res.data;
if(this.goods_detail) {
this.getGoodsBackground()
if(this.pt == 2) {
this.bindGoods()
}
}
this.afterDone = this.formatRichText(this.goods_detail.content)
this.is_collect = Boolean(res.data.user.is_collect);
}).catch(err => {
this.skeletonLoading = false;
setTimeout(() => {
that.$toBack();
}, 1000);
})
},
// 切换商品收藏
switchCollect() {
let userInfo = uni.getStorageSync('userinfo') || {};
if (!userInfo.id || !userInfo.nickname || !userInfo.avatar) {
this.$url('/pages/login/index?type=userinfo');
return;
}
this.$http(this.API.API_COLLECT_DEAL, {
goods_id: this.goods_id
}).then(res => {
this.$msg(res.msg);
this.is_collect = Boolean(res.data.user.is_collect);
})
},
// 拨打电话
makePhoneCall(phoneStr) {
uni.makePhoneCall({
phoneNumber: String(phoneStr)
})
},
// 打开地图
openMap(){
let { address, lat, lng } = this.goods_detail?.store || {};
uni.openLocation({
longitude: Number(lat),
latitude: Number(lng),
scale: 20,
name: address
});
},
// 跳转到确认下单页面
toAddOrder() {
let goods_id = this.goods_detail.id;
let goods_specs_id = this.goods_detail.specs[0].id
this.$url('/pages/order/confirm-order?goods_id=' + goods_id + '&goods_specs_id=' + goods_specs_id +'&pt='+ this.pt +'&share_id='+ this.s_id);
},
// 预览图片
lookImg(index) {
this.$u.throttle(() => {
let goods_banner = this.goods_detail.banners || [];
let banners = goods_banner.map(item => item.cover);
uni.previewImage({
urls: banners,
current: index
})
}, 200);
},
// 富文本处理
formatRichText(richText) {
if (richText != null) {
let newRichText = richText.replace(/<img[^>]*>/gi, function(match, capture) {
match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '');
match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '');
match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '');
return match;
});
newRichText = newRichText.replace(/style="[^"]+"/gi, function(match, capture) {
match = match.replace(/width:[^;]+;/gi, 'width:100%;').replace(/width:[^;]+;/gi,
'width:100%;');
return match;
});
newRichText = newRichText.replace(/<br[^>]*\/>/gi, '');
newRichText = newRichText.replace(/\<img/gi,
'<img style="width:100%;height:auto;display:block;margin:10px 0;"');
return newRichText;
} else {
return null;
}
},
// 将token上传到后端
generateKooken(token, options){
options.version = this.API.VERSION;
let values = JSON.stringify(options);
values = encodeURIComponent(values);
this.$http(this.API.API_WAREHOUSE_SET, {
key: token,
value: values
}).then(res => {
console.log("res", token, res);
});
}
},
onShareAppMessage() {
const token = this.$shared.createToken({
user_id: this.userInfo.id,
goods_id: this.goods_id
});
let goods = this.goods_detail;
let options = {
id: goods.id,
route: 'goods',
scene_code: this.$scene.V2_GOODS_SHAREPOSTER
}
this.generateKooken(token, options); // 谁分享了就生成一个token
// let goods = this.goods_detail;
// let title = goods.name;
// let imageUrl = goods.share_cover || goods.cover;
// let path = '/pages/route/index?route=goods_detail&id=' + goods.id;
let title = goods.name;
let imageUrl = goods.share_cover || goods.cover;
let path = '/pages/route/index?token='+ token;
return {
title,
path,
imageUrl
}
}
}
</script>
<style>
page {
background-color: #f5f5f5;
overflow-x: hidden;
}
</style>
<style lang="scss" scoped="scoped">
.bill-position {
position: absolute;
top: 0;
right: 0;
}
.cu-btn1 {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 0 30rpx;
font-size: 28rpx;
height: 64rpx;
line-height: 1;
text-align: center;
text-decoration: none;
overflow: visible;
margin-left: initial;
transform: translate(0upx, 0upx);
margin-right: initial;
background-color: rgba(0, 0, 0, 0.5);
color: #FFFFFF;
border-radius: 33rpx;
}
.swiper-box {
width: 750rpx;
height: 520rpx;
background-color: #FFFFFF;
}
.head-info {
width: 750rpx;
height: auto;
box-sizing: border-box;
padding: 0 32rpx;
padding-top: 20rpx;
background-color: #FFFFFF;
// .price>view:nth-of-type(1){
// color: #FF0000;
// margin-right: 22rpx;
// font-weight: bold;
// }
.price>view:nth-of-type(1) {
text-decoration: line-through;
color: #777777;
margin-right: 22rpx;
}
.price>view:nth-of-type(2) {
width: max-content;
padding: 0 18rpx;
height: 46rpx;
background-color: #FE9903;
border-radius: 10rpx;
display: flex;
justify-content: center;
align-items: center;
color: #FFFFFF;
}
.label-box {
min-height: 130rpx;
width: 100%;
border-top: 1rpx solid #E5E5E5;
display: flex;
flex-wrap: wrap;
padding: 30rpx 0 10rpx 0;
.label-item {
width: 156rpx;
height: 70rpx;
border-radius: 10rpx;
border: 2rpx solid #FE9903;
display: flex;
justify-content: center;
align-items: center;
font-size: 28rpx;
color: #FE9903;
margin-right: 20rpx;
margin-bottom: 20rpx;
}
}
}
.address-box {
width: 750rpx;
height: auto;
box-sizing: border-box;
background-color: #FFFFFF;
padding: 32rpx;
margin-top: 20rpx;
.shop-img {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
}
}
.goods-detail {
width: 750rpx;
height: auto;
background-color: #FFFFFF;
padding: 32rpx;
box-sizing: border-box;
margin-top: 20rpx;
.goods-img {
width: 100%;
}
}
.extra {
width: 100%;
height: 120rpx;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
box-sizing: content-box;
}
.fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
z-index: 99;
background-color: #FFFFFF;
width: 100%;
height: auto;
padding: 0 32rpx;
border-top: 1rpx solid #e5e5e5;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.icon-item {
margin-right: 16rpx;
background-color: transparent;
margin: 0;
line-height: initial;
font-size: 28rpx;
font-weight: inherit;
margin-right: 10rpx;
padding: 0;
width: 88rpx;
&:first-child {
padding-left: 0;
}
.icon-img {
height: 50rpx;
width: 50rpx;
}
}
.btn {
margin: 0;
padding: 0;
width: 208rpx;
height: 80rpx;
background-color: #FE9903;
color: #FFFFFF;
line-height: 80rpx;
font-size: 32rpx;
border-radius: 42rpx;
}
}
//海报
.bgImg {
display: block;
width: 100%;
height: 366rpx;
}
.mine {
display: block;
text-align: center;
color: #333;
margin-top: 44rpx;
}
.code {
display: block;
text-align: center;
color: #333;
font-size: 76rpx;
font-weight: bold;
margin-top: 30rpx;
}
.who {
display: block;
margin-top: 80rpx;
font-size: 32rpx;
color: #333;
text-align: center;
}
.inputBox {
text-align: center;
margin-top: 44rpx;
}
.input {
text-align: center;
width: 440rpx;
height: 88rpx;
border-radius: 44rpx;
background: #f5f5f5;
font-size: 32rpx;
display: inline-block;
}
.btn {
width: 160rpx;
height: 88rpx;
border-radius: 44rpx;
background: rgba(254, 153, 3, 1);
color: #333;
font-size: 32rpx;
display: inline-block;
line-height: 88rpx;
margin-left: 40rpx;
}
button[class="btn"]::after {
border: 0;
}
.tishi {
display: block;
text-align: center;
color: #999;
margin-top: 30rpx;
}
.shareText {
display: block;
text-align: center;
color: #333;
font-size: 28rpx;
margin-top: 100rpx;
}
.imgBox {
text-align: center;
width: 100%;
margin-top: 60rpx;
padding-bottom: 120rpx;
}
.img {
display: inline-block;
width: 100%;
height: 100%;
}
.m_l {
margin-left: 180rpx;
}
.zfbtn {
display: inline-block;
width: 120rpx;
height: 120rpx;
border-radius: 50%;
background: transparent;
outline: none;
border: 0;
padding: 0;
}
button[class="zfbtn"]::after {
border: 0;
}
button[class="zfbtn m_l"]::after {
border: 0;
}
.imagePathBox {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
}
.shengcheng {
width: 80%;
height: 80%;
position: fixed;
// top: 50rpx;
top: 140rpx;
left: 50%;
margin-left: -40%;
z-index: 100;
}
.baocun {
display: block;
width: 80%;
height: 80rpx;
padding: 0;
line-height: 80rpx;
text-align: center;
position: fixed;
bottom: 100rpx;
left: 10%;
background: rgba(254, 153, 3, 1);
color: #fff;
font-size: 32rpx;
border-radius: 44rpx;
}
button[class="baocun"]::after {
border: 0;
}
</style>