1802 lines
46 KiB
Vue
Raw Normal View History

2025-05-08 09:16:37 +08:00
<template>
<div>
<view class="goods-bar" :class="color ? 'goods-box' : ''" :style="{'height': customVal.height + 'px;padding:' + customVal.top + 'px 15px ' + (customVal.top - statusBarHeight) + 'px;'}">
<view class="icon flex" v-if="pagesLength === 1" @click="toPage('/pages/index/index')">
<up-icon name="home" size="18" color="#333" />
</view>
<view class="icon flex" v-if="pagesLength > 1" @click="toBack()">
<up-icon name="arrow-left" size="18" color="#333" />
</view>
</view>
<div style="padding-bottom: 130rpx;">
<div :style="tableList.status === 3 ? 'padding-bottom: 60rpx;' : ''">
<div class="home-top ">
<swiper class="home-top-swiper" :autoplay="true" :interval="5000" :duration="500" :indicator-dots="true" :circular="true">
<swiper-item v-for="(item, index) in tableList.gallery" :key="index">
<image class="item_img" :src="item + '?x-oss-process=image/format,webp'" :webp="true" mode="aspectFill"></image>
</swiper-item>
</swiper>
</div>
<div class="title">
<div class="price">
<!-- 活动图片 -->
<div class='move_img' v-if="tableList.active && tableList.active.name && tableList.active.type != 1">{{tableList.active.name}}</div>
<div class="szie">{{tableList.title}}</div>
<div class="color">
<span v-if="tableList.price < 0"></span>
<div class="font">
<block v-if="tableList.price > 0">
<text>{{tableList.price}}</text>
</block>
<block v-else>
<text v-if="tableList.max_price === tableList.min_price">{{tableList.min_price}}</text>
<text
v-else-if="parseInt(tableList.max_price) < parseInt(tableList.min_price)">{{tableList.max_price}}~{{tableList.min_price}}</text>
<text v-else>{{tableList.min_price}}~{{tableList.max_price}}</text>
</block>
</div>
<div class="huaxin" v-if="tableList.market_price * 1 != 0">{{tableList.market_price}}</div>
<div class='move_endTime' v-if="confidence.sold_start_time || confidence.sold_off_time">
{{timeIngType}} {{days}}
<text class="sfm-warp sfm-warp1">{{hours}}</text>&nbsp;:&nbsp;
<text class="sfm-warp">{{mins}}</text>&nbsp;:&nbsp;
<text class="sfm-warp">{{seconds}}</text>
</div>
</div>
</div>
<div><button open-type="share" class="share"><up-icon name="share" :color="Color" size='25' /></button></div>
</div>
<div class="SKU" @click="tableList.status == 1 ? hanleClik(tableList.specs_type) : ''">
<div style="font-size: 26rpx;font-weight: 600;">选择: &nbsp;</div>
<div class="sku_list">
<div class="name">{{name || '商品规格'}}</div>
<up-icon name="arrow-right" color='#676767' />
</div>
</div>
<view class="shipbox" @click="showFahuo = true" v-if="confidence.ship_address || (confidence.ship_time_type && confidence.ship_time_type != 0)">
<view class="row"><text>发货: &nbsp;</text>
<template v-if="confidence.ship_address">{{confidence.ship_address}}发货&nbsp;|&nbsp;</template>
<template v-if="confidence.ship_time_type && confidence.ship_time_type != 0">最晚于{{shipType[confidence.ship_time_type]}}停发地区发货时效不确定</template>
</view>
<up-icon name="arrow-right" size="14" color="999" />
</view>
<view class="commentBox" v-if="commentTotal > 0">
<view class="toptitle">
<text class="num">商品评价({{commentTotal}})</text>
<view class="more" @click="hanleEvaluations()">
好评率{{goodCommentRate}}<up-icon name="arrow-right" size="14" color="#999" />
</view>
</view>
<view class="commentlist">
<view class="item" v-for="itm in commentList" :key="itm.id">
<view class="itemtop">
<view class="user">
<image :src="itm.user.avatar" class="avatar"></image>
<view class="right">
<view>
<text class="name">{{itm.user && itm.user.nickname}}</text>
<text class="border">已购{{itm.report && itm.report.total_trade_count}}</text>
</view>
<view class="rate">
<view class="star" v-for="i in 5">
<up-icon v-if="i <= Math.ceil(itm.stars)" name="star-fill" color="#FFD81E" size="14" />
<up-icon v-else name="star" color="#ccc" size="14" />
</view>
</view>
</view>
</view>
<view class="date">{{itm.date.replace(/-/g, '/')}}发布于{{provTxt[itm.order.province_id]}}</view>
</view>
<view v-if="itm.item.sku_name" style="font-size: 24rpx;color: #999;margin-top: 16rpx;">
规格{{itm.item.sku_name}}
</view>
<view class="text">{{itm.comment}}</view>
<div class="box_zong" v-if="itm.material.length">
<view class="box_imgs" v-for="(it, index) in itm.material" :key="index">
<div v-show="index < 3">
<image :src="it.url" mode="aspectFill" v-if="it.type === 1" @click="hanleImgs(it, itm.material)"></image>
</div>
</view>
</div>
</view>
</view>
</view>
<view class="goods-comment" v-if="merchant_id">
<div class="goodslist" @click="hanleJump1">
<div class="goodsbox">
<image :src="confidence.logo" mode="aspectFit" alt="" />
<div class="tit">{{confidence.name}}</div>
</div>
<div class="goodslistbox">
<div>全部商品 {{totallist}}
<up-icon name="arrow-right" size='14' color='#676767' />
</div>
</div>
</div>
<div class="goodscommodity">
<div class="goodsgun" v-for="(item, index) in storelist" :key="index" @click="hanleJump(item.id)">
<div><image :src="item.face_img + '?x-oss-process=image/format,webp'" :webp="true" mode="aspectFill"></image></div>
<div class="title_list">{{item.title}}</div>
<div class="price_list">
<text class="icon"></text>
<block v-if="item.price > 0">
<text>{{item.price}}</text>
</block>
<block v-else>
<text v-if="item.max_price === item.min_price">{{item.min_price}}</text>
<text v-else-if="parseInt(item.max_price) < parseInt(item.min_price)">{{item.max_price}}~{{item.min_price}}</text>
<text v-else>{{item.min_price}}~{{item.max_price}}</text>
</block>
<!-- <div class="market_price"> <text class="icon"></text>{{item.market_price}}</div> -->
</div>
</div>
</div>
</view>
<view class="goods_param" v-if="tableList.goods && tableList.goods.goods_params">
<view class="tit">商品参数</view>
<view class="content">
<text>{{tableList.goods.goods_params.replace(/↵/g, '\n')}}</text>
</view>
</view>
<!-- 简单编辑器 -->
<view class="edition">
<div v-for="(item, index) in tableList.text_modules" :key="item.id">
<div class="edition_box big" v-if="item.type == 1" @click="preViewImg(item.imgs[0])">
<div v-for="(imgs, index) in item.imgs" :key="index">
<image :src="imgs + '?x-oss-process=image/format,webp'" :webp="true" mode="widthFix" style="height:100%;width:100%" class="image"></image>
</div>
</div>
<div class="edition_box" v-if="item.type == 2">
<div class="small_img">
<div v-for="(list, index1) in item.img" :key="index1" class="imgs" @click="preViewImg(list)">
<image :src="list + '?x-oss-process=image/format,webp'" mode="aspectFill" :webp="true"></image>
</div>
</div>
</div>
<div class="edition_box" v-if="item.type == 3" @longpress="toSave(item.video[0])"
@click="hanlevedio(item.video[0])">
<div class="background flex">
<up-icon name="play-right-fill" size="42" color="#fff" />
</div>
<image :src="item.video_img" mode="widthFix" style="height:100%;width:100%"></image>
</div>
<div class="edition_box text1_box" v-if="item.type == 4">
<text selectable="true" user-select="true" class="text">{{item.text}}</text>
</div>
</div>
</view>
<div class="introduction">
<div class="titles" style='color: #999999;'>价格说明</div><br />
<div class="paragraph">
<div class="point"></div>
<div class="titl" style='color: #999999;'>划线价格</div>
</div>
<div class="goods_info" style='color: #999999;'>商品的专柜价吊牌价正品零售价厂商指导价或该商品的曾经展示过的销售价等,<text
class="paragraph" style='color: #666666;font-weight: 700;'>并非原价</text>,仅供参考</div><br />
<div class="paragraph">
<div class="point"></div>
<div class="titl" style='color: #999999;font-weight: 700;'>未划线价格</div>
</div><br />
<div class="goods_info" style='color: #999999;'>商品的<text class="paragraph"
style='color: #999999;font-weight: 700;'>实时标价</text>,不因表述的差异改变性质具体成交价格根据商品参加活动,或会员使用优惠券积分等发生变化,最终以订单结算页价格为准
</div>
</div>
<div class="recommend" v-if="recommendList.length">
<div style="width: 100%; text-align: center; padding: 40rpx 0;">
<image src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2024/06/04/46htQZUX302oWnlo09LHUlbUL0gt1VaWftK34mUl.png"
style="width: 180px; height: 18px;"></image>
</div>
<div class="box_tite">
<div v-for="(item, index) in recommendList" :key="index" class="hezi" @click.stop="hanleJump(item.id)">
<image :src="item.face_img + '?x-oss-process=image/format,webp'" :webp="true" mode="aspectFill" />
<div class="zong">
<div class="tit">{{item.title}}</div>
<div class="number">
<text class="icon"></text>
<block v-if="item.price > 0">
<text>{{item.price}}</text>
</block>
<block v-else>
<text v-if="item.max_price === item.min_price">{{item.min_price}}</text>
<text v-else-if="parseInt(item.max_price) < parseInt(item.min_price)">{{item.max_price}}~{{item.min_price}}</text>
<text v-else>{{item.min_price}}~{{item.max_price}}</text>
</block>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="foot">
<div class="tite" v-if="tableList.status == 3">该商品已下架或临时下架</div>
<div class="foot_list">
<div class="foot_noe">
<div class="noe" @click="toPage('/pages/index/index')"><up-icon name="home" size="20" />首页</div>
<div class="noe" @click="showService = true"><up-icon name="kefu-ermai" size="20" />客服</div>
<div class="noe" @click="toPage('/pages/cart/index')">
<view class="flex" style="height: 20px;">
<up-icon name="shopping-cart" size="25" />
</view>购物车
<div class="shuliang" v-if="number">{{ number }}</div>
</div>
</div>
<view class="remind flex" v-if="timeIngType == '距开始'" :class="tableList.is_subscribe_remind ? 'disabled' : ''" @click="remindUser">
<view v-if="!tableList.is_subscribe_remind" class="topone">预约提醒</view>
<view v-else class="topone">已提醒</view>
<view class="bot">距开始{{days}}{{hours}}{{mins}}{{seconds}}</view>
</view>
<div v-else class="foot_two">
<div class="car flex" :class="tableList.status == 1 ? '' : 'car_active1'"
@click="tableList.status == 1 ? hanlesku(tableList.specs_type, 1) : ''">加入购物车</div>
<div class="group flex" :class="tableList.status == 1 ? '' : 'car_active'"
@click="tableList.status == 1 ? hanlesku(tableList.specs_type, 2) : ''">立即购买</div>
<!-- <button v-else class="group" :class="tableList.status==1?'':'car_active'" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber($event)">立即购买</button> -->
</div>
</div>
</div>
<van-share :show-share="showShare" @creatShare="creatShare" @getLink="shareLink" @close="showShare = false" />
<creat-poster v-if="showImg" :posterImg="posterImg" @closeShow="showImg = false" />
<oneSku :sku_noe="sku_noe" :source="source" :type="type" :SKU='SKU' @getnum="getnum1" @remind="remindAction" @close1="close1" v-if="tableList.specs_type == 0" />
<twoSku :sku_two="sku_two" :source="source" v-else :SKU='SKU' @getnum="getnum" @remind="remindAction" @skunoe="skunoe" :type="type" @close="close" />
<up-popup :show="showSaleGoods" :round="10" mode="bottom" @close="showSaleGoods = false" catchtouchmove="preventD">
<view class="sale-goods">
<view class="tit">货物地址及选品员</view>
<view class="sale-goods-item">
<view class="item">
<text>商品信息{{saleGoodsInfo.title}}</text>
</view>
<view class="item" v-if="saleGoodsInfo.goods && saleGoodsInfo.goods.refund_address">
<text>退货地址{{saleGoodsInfo.goods && saleGoodsInfo.goods.refund_address}}</text>
<text class="copy" @click="copyBtn(saleGoodsInfo.goods && saleGoodsInfo.goods.refund_address)">复制</text>
</view>
<view class="item">
产品经理{{saleGoodsInfo.goods && saleGoodsInfo.goods.manager.username}}
</view>
<view class="item">
跟品经理{{saleGoodsInfo.goods && saleGoodsInfo.goods.follow_manager.username}}
</view>
<view class="price">
商品价格
<block v-if="saleGoodsInfo.specs_type === 0">
<text class="commission">{{saleGoodsInfo.price}}</text>
<text style="margin-left: 20rpx;">佣金</text>
<text class="commission">{{saleGoodsInfo.sale_profit}}</text>
<text style="margin-left: 20rpx;">百分率</text>
<text class="commission">{{saleGoodsInfo.sale_profit_rate}}</text>
</block>
<block v-else-if="saleGoodsInfo.specs_type === 1">
<view class="sku" v-for="(sku, index) in saleGoodsInfo.skus" :key="index">
<div v-if="index<100">
<text>{{sku.v1}}</text>
<text v-if="sku.v2">{{' ' + sku.v2}}</text>
<text v-if="sku.v3">{{' ' + sku.v3}}</text>
<text class="commission">{{sku.price}}</text>
<text style="margin-left: 20rpx;">佣金</text>
<text class="commission">{{sku.sale_profit}}</text>
<text style="margin-left: 20rpx;">百分率</text>
<text class="commission">{{sku.sale_profit_rate}}</text>
</div>
</view>
</block>
</view>
</view>
<view class="btnbox"><view class="btn flex" @click="showSaleGoods = false">好的</view></view>
</view>
</up-popup>
<up-popup :show="showFahuo" :round="10" mode="bottom" @close="showFahuo = false">
<div class="popup">
<div style="font-size: 34rpx;text-align: center;border-bottom: 1rpx solid #E5E5E5;padding: 20rpx;">发货</div>
<div style="padding:30rpx;font-size: 28rpx;line-height: 54rpx;height: 50vh;overflow-y: auto;">
<template v-if="confidence.ship_address">{{confidence.ship_address}}发货&nbsp;|&nbsp;</template>
<template v-if="confidence.ship_time_type && confidence.ship_time_type != 0">最晚于{{shipType[confidence.ship_time_type]}}停发地区发货时效不确定</template>
</div>
<view class="cancel" @click="showFahuo = false">好的</view>
</div>
</up-popup>
<video-dialog :url="video" :show="show_video" @close="show_video = false"></video-dialog>
<div class="top" v-show="show_top">
<div @click="hanletop" class="top_noe flex">
<up-icon name="arrow-upward" color="#000" size="20" />
</div>
</div>
<!-- 客服 -->
<call-center :show="showService" @close="showService = false" :type="1" />
<!-- 店铺管理员显示团购群聊分享文案 -->
<up-popup :show="showManagerCase" closeable @close="showManagerCase = false" catchtouchmove="preventD" mode="center"
:closeOnClickOverlay="false" :customStyle="customStyle">
<view class="caseBox">
<view class="tit">{{scoreShareInfo.user && scoreShareInfo.user.nickname}}
本次分享积分+{{scoreShareInfo.share_score * 1}}累计可用积分{{scoreShareInfo.user && scoreShareInfo.user.score * 1}}
积分可以兑换优惠券
</view>
<view class="copycase flex" @click="copyScoreCase">复制文案去群内播报</view>
</view>
</up-popup>
<!-- 团购群聊分享文案 -->
<up-popup :show="showCase" :customStyle="customStyle" catchtouchmove="preventD" :closeOnClickOverlay="false" mode="center">
<view class="caseBox">
<view class="title1">您的跟团分享社群积分已到账</view>
<view class="num">积分<text>+{{scoreShareInfo.share_score * 1}}</text></view>
<view class="copycase flex" @click="showCase = false">知道了</view>
</view>
</up-popup>
<!-- 隐私协议弹窗 -->
<privacy-popup :show-dialog="showPrivacy" @close="showPrivacy = false" @agree="showPrivacy = false" @refuse="showPrivacy = false" />
</div>
</template>
<script>
import { getImg, login, getUserPhone, getShopInfo, UpTime, DownTime, userBind, judgePrivacy, downloadVideo, toMiniProgram } from '@/components/common.js'
import { ref, reactive, toRefs } from 'vue'
import { get, post } from '@/api/request.js'
import oneSku from './one.vue'
import twoSku from './two.vue'
import vanShare from '@/components/share/vanShare.vue'
import creatPoster from '@/components/share/creatPoster.vue'
import callCenter from '@/components/callCenter/index.vue'
import { Style } from '@/utils/list.js'
import privacyPopup from '@/components/privacyPopup/index.vue'
import videoDialog from '@/components/videoDialog/index.vue'
import { provTxt } from '@/components/scene.js'
export default {
components: {
oneSku,
twoSku,
vanShare,
creatPoster,
callCenter,
privacyPopup,
videoDialog
},
setup() {
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight
const data = reactive({
page: 1,
lastPage: 0,
show_top: false,
saleGoodsInfo: '',
role: 0,
Url_image: '',
shareUrl: '',
tableList: '', //数据
id: '', //id
sku_two: false, //多规格
sku_noe: false, //单规格
type: 0, //1加入购物车 2立即购买
pagesLength: 0,
color: false,
needArticleList: [], // 富文本
commentList: [], //评论
goodCommentRate: '',
commentTotal: '',
merchant_id: 0, //小店id
storelist: [], //小店推荐
totallist: 0, //总数
confidence: {}, //店铺信息
sale_id: '', //销售id
s: '',
u: '',
company_id: '',
category_id: '', //分类id
recommendList: [], //推荐列表
SKU: {}, //规格
number: '', //数量
name: '',
showSaleGoods: false, //推荐商品
show_video: false,
video: '',
days: '00', //天
hours: '00',
mins: '00',
seconds: '00',
showShare: false,
showImg: false,
posterImg: '',
endtime: '',
timeIng: 0,
timeIngType: '',
downFn: null,
isNoStart: false,
shipType: {
'1': '48小时内',
'2': '72小时内',
'3': '7天内'
},
showFahuo: false,
showService: false,
is_authorized: uni.getStorageSync('is_authorized'),
source: '',
remindTmplId: '',
showManagerCase: false,
customStyle: {
width: '86%',
'border-radius': '10px'
},
showCase: false,
pay_id: '',
scoreShareInfo: {},
Color: '',
Theme: '',
tagColor: '',
priceColor: '',
customVal: uni.getMenuButtonBoundingClientRect(),
showPrivacy: false
})
const hanletop = () => {
uni.pageScrollTo({
scrollTop: 0,
duration: 300
})
}
const hanlevedio = (e) => {
data.show_video = true
data.video = e
}
// 预览图片
const preViewImg = (img) => {
let img_preview_suffix = uni.getStorageSync('img_preview_suffix') || ''
let imurl = img + img_preview_suffix
if(img.indexOf('.gif') >= 0 || img.indexOf('.GIF') >= 0) {
imurl = img
}
uni.previewImage({
urls: [imurl],
current: 0
})
}
// 复制
async function copyBtn(val) {
if(await judgePrivacy()) {
data.showPrivacy = true
return false
}
uni.setClipboardData({
data: val
})
}
const skunoe = (e) => {
data.name = e
}
//推荐列表
const getTop = async () => {
uni.showLoading({
title: '加载中...'
})
await get('/api/v1/special/goods/hot', {
category_id: data.category_id,
page: data.page
}).then((res) => {
data.lastPage = res.meta.last_page
data.recommendList = data.recommendList.concat(res.data)
uni.hideLoading()
})
}
//获取商品详情
const getProduct = async () => {
const res = await get(`/api/v1/goods/spec/${data.id}`)
data.SKU = res.data
if(data.isNoStart) {
data.SKU.isNoStart = 1
data.SKU.remind = data.tableList.is_subscribe_remind
data.SKU.sold_start_time = data.confidence.sold_start_time
}
}
//导航栏图标
let pages = getCurrentPages()
data.pagesLength = pages.length
//数据
const getlist = async () => {
let res = await get(`/api/v1/goods/detail/${data.id}`)
data.merchant_id = res.data.merchant_id
data.tableList = res.data
data.category_id = res.data.goods && res.data.goods.category_id
if (res.data.text) {
data.tableList.text = res.data.text.replace(
/\<img/gi,
'<img style="max-width:100%; display: block;"'
)
data.tableList.text = res.data.text.replace(
/\<video/gi,
'<video style="width:100px !important;"'
)
}
// 解析富文本video
let videoList = []
let videoReg = /<video.*?(?:>|\/>)/gi //匹配到字符串中的 video 标签
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i //匹配到字符串中的 video 标签 的路径
let arr = data.tableList.text.match(videoReg) || [] // arr 为包含所有video标签的数组
let articleList = data.tableList.text.split('</video>') // 把字符串 从视频标签分成数组
arr.forEach((item, index) => {
var src = item.match(srcReg)
if (src != null) {
videoList.push(src[1]) //所要显示的字符串中 所有的video 标签 的路径
}
})
data.needArticleList = []
articleList.forEach((item, index) => {
if (item != '' && item != undefined) {
// 常见的标签渲染
data.needArticleList.push({
type: 'rich-text',
value: item + '</video>',
})
if (data.needArticleList[index].type == 'rich-text') {
let str = data.needArticleList[index].value
str = str.split(videoReg)
data.needArticleList[index].value = str[0]
}
}
let articleListLength = articleList.length // 插入到原有video 标签位置
if (index < articleListLength && videoList[index] != undefined) {
data.needArticleList.push({
type: 'video',
value: videoList[index]
})
}
})
}
const toSave = (url) => {
uni.showActionSheet({
itemList: ['保存视频'],
success: (res) => {
downloadVideo(url)
},
fail: (err) => {}
})
}
//评价
const getcomment = async () => {
await get(`/api/v1/goods/comment/${data.id}`, {
pageSize: 2,
type: 0
}).then((res) => {
data.commentList = res.data
data.goodCommentRate = res.goodCommentRate
data.commentTotal = res.meta.total
})
}
// 小店团购
const getmerchantId = async () => {
if(data.merchant_id) {
await get(`/api/v1/merchant/goods/${data.merchant_id}`, {
pageSize: 8
}).then((res) => {
data.storelist = res.data
data.totallist = res.meta.total
})
}
}
// 小店信息
async function getBoxtitle() {
if(data.merchant_id) {
await get(`/api/v1/merchant/${data.merchant_id}`).then((res) => {
data.confidence = res.data
getTimeIng(res.data.sold_start_time, res.data.sold_off_time)
})
}
}
//评论图片预览
const hanleImgs = (e, list) => {
var img = []
list.forEach((res) => {
if (res.type == 1) {
img.push(res.url)
}
})
if (e.type === 1) {
uni.previewImage({
current: e.url, // 当前显示图片的链接
urls: img
})
}
}
//返回首页
function toPage(url) {
uni.switchTab({
url
})
}
//返回上一级
function toBack() {
uni.navigateBack({
delta: 1
})
}
//跳转评论
function hanleEvaluations() {
uni.navigateTo({
url: '/pages/groups/comment?id=' + data.id
})
}
//跳转小店
function hanleJump(id) {
uni.navigateTo({
url: '/pages/productDetails/index?id=' + id
})
}
//跳转商品详情
function hanleJump1() {
uni.navigateTo({
url: '/pages/smallshop/index?id=' + data.merchant_id
})
}
//打开sku
function hanleClik(e) {
data.type = 0
if (e == 0) {
data.sku_noe = true
} else {
data.sku_two = true
}
}
//关闭多规格
function close(e) {
data.sku_two = e
}
//关闭单规格
function close1(e) {
data.sku_noe = e
}
//加入购物车或立即购买打开sku
function hanlesku(id, e) {
data.type = e
if (id == 0) {
data.sku_noe = true
} else {
data.sku_two = true
}
}
const getShareUrl = () => {
post('/api/v1/user/share', {
page: 'pages/productDetails/index',
query: `id=${data.id}`
}).then((res) => {
data.shareUrl = res.data.path
})
}
const getshare = () => {
get(`/api/v1/goods/share/${data.id}`, {
type: 1
}).then((res) => {
data.Url_image = res.data.image
})
}
const getCartList = () => {
get('/api/v1/carts').then((res) => {
data.number = res.num
uni.setStorageSync('cartNum', res.num)
})
}
const getnum = (e, id) => {
data.name = e
getCartList()
}
const remindAction = () => {
data.tableList.is_subscribe_remind = true
}
const getnum1 = (e) => {
getCartList()
}
const showGoodsInfo = () => {
data.showSaleGoods = true
getSalesGoodsInfo()
}
const getSalesGoodsInfo = async () => {
let res = await get(`/api/v1/sales/goods/${data.id}`)
data.saleGoodsInfo = res.data
}
// 复制链接
const shareLink = async () => {
if(await judgePrivacy()) {
data.showPrivacy = true
return false
}
post('/api/v1/user/link/short', {
page: 'pages/productDetails/index',
shop_goods_id: data.id
}).then((res) => {
uni.setClipboardData({
data: res.data.link,
success: () => {
uni.showToast({
title: '复制成功',
icon: 'none'
})
}
})
})
}
// 生成海报
const creatShare = () => {
uni.showLoading({
title: '海报生成中...'
})
get(`/api/v1/goods/share/${data.id}`, {
type: 7
}).then((res) => {
data.posterImg = res.data.image
uni.hideLoading()
data.showImg = true
})
}
//倒计时函数
function DownTime1(endTime, type) {
if (!endTime) {
data.days = '00'
data.hours = '00'
data.mins = '00'
data.seconds = '00'
return
} else {
var downFn = setInterval(() => {
var to = new Date(endTime.replace(/-/g, "/"));
var now = new Date();
var backTime = to.getTime() - now.getTime();
var d = Math.floor(backTime / (1000 * 60 * 60 * 24)); //计算天数
var h = Math.floor(backTime / (1000 * 60 * 60) % 24); //计算小时数
var m = Math.floor(backTime / (1000 * 60) % 60); //计算分钟数
var s = Math.floor(backTime / 1000 % 60); //计算秒数
if (backTime < 0) {
data.days = '00'
data.hours = '00'
data.mins = '00'
data.seconds = '00'
clearInterval(downFn)
} else {
data.days = d > 9 ? d : '0' + d
data.hours = h > 9 ? h : '0' + h
data.mins = m > 9 ? m : '0' + m
data.seconds = s > 9 ? s : '0' + s
}
}, 1000)
}
}
function getTimeIng(startTime, endTime) {
// 如果开始时间存在,结束时间不存在,判断活动是否开始
if(startTime && !endTime){
let st = new Date(startTime.replace(/-/g, '/'))
let nt = new Date().getTime()
if(nt - st < 0) {
data.timeIng = st - nt
data.timeIngType = '距开始'
data.isNoStart = true
setTimeIng(data.timeIng)
}
}
// 如果开始时间不存在,结束时间存在,判断活动是否结束
if(!startTime && endTime) {
let et = new Date(endTime.replace(/-/g, '/'))
let nt = new Date().getTime()
if(et - nt > 0) {
data.timeIng = et - nt
data.timeIngType = '距结束'
setTimeIng(data.timeIng)
}
}
// 如果开始时间、结束时间存在
if(startTime && endTime) {
let nt = new Date().getTime()
let st = new Date(startTime.replace(/-/g, '/'))
let et = new Date(endTime.replace(/-/g, '/'))
if(nt <= st) {
data.timeIng = st - nt
data.timeIngType = '距开始'
data.isNoStart = true
setTimeIng(data.timeIng)
}
if(st < nt && nt < et) {
data.timeIng = et - nt
data.timeIngType = '距结束'
setTimeIng(data.timeIng)
}
}
}
function setTimeIng(backTime) {
data.downFn = setInterval(() => {
var d = Math.floor(backTime / (1000 * 60 * 60 * 24)); //计算天数
var h = Math.floor(backTime / (1000 * 60 * 60) % 24); //计算小时数
var m = Math.floor(backTime / (1000 * 60) % 60); //计算分钟数
var s = Math.floor(backTime / 1000 % 60); //计算秒数
if (backTime < 0) {
data.days = '00'
data.hours = '00'
data.mins = '00'
data.seconds = '00'
data.timeIngType = ''
data.timeIng = 0
data.isNoStart = false
clearInterval(data.downFn)
} else {
data.days = d > 9 ? d : '0' + d
data.hours = h > 9 ? h : '0' + h
data.mins = m > 9 ? m : '0' + m
data.seconds = s > 9 ? s : '0' + s
}
backTime -= 1000
}, 1000)
}
function getRemindTempId() {
get(`/api/v1/shop/template`, { type: 20 }).then((req) => {
data.remindTmplId = req.data.template_id
})
}
function remindUser() {
toMiniProgram('pages/productDetails/index?id=' + data.id)
}
// 授权手机号码
async function getPhoneNumber(e) {
if(e.detail.errMsg == 'getPhoneNumber:ok') {
await getUserPhone(e.detail).then((res) => {
data.is_authorized = 1
})
}
}
// 获取积分群分享
function receiveScoreShare() {
post('/api/v1/shopScore/share/receive', { pay_id: data.pay_id }).then((res) => {
// 1下单人 2下单人当前销售 其他人返回值为空数组
if(res.data.length === 0) {
} else {
data.scoreShareInfo = res.data
if(res.data.click_type === 1) {
data.showCase = true
}
if(res.data.click_type === 2) {
data.showManagerCase = true
}
}
})
}
// 复制文案去群内播报
async function copyScoreCase() {
if(await judgePrivacy()) {
data.showPrivacy = true
return false
}
let text = '「' + (data.scoreShareInfo.user && data.scoreShareInfo.user.nickname)
+ '」本次分享积分+' + data.scoreShareInfo.share_score * 1
+ ',累计可用积分' + (data.scoreShareInfo.user && data.scoreShareInfo.user.score) * 1
+ ',积分可以兑换优惠券'
uni.setClipboardData({
data: text,
success: function () {
uni.showToast({
icon: 'none',
title: '文案已复制'
})
},
fail: function () {
uni.showToast({
icon: 'none',
title: '复制失败'
})
}
})
}
const preventD = () => {
return
}
return {
getShopInfo,
provTxt,
toMiniProgram,
...toRefs(data),
statusBarHeight,
getShareUrl,
getshare,
userBind,
toPage,
toBack,
getcomment,
hanleEvaluations,
hanleJump,
hanleJump1,
getImg,
hanleClik,
close,
close1,
hanlesku,
getlist,
hanleImgs,
getmerchantId,
getBoxtitle,
toSave,
getTop,
getProduct,
getnum,
getCartList,
skunoe,
getnum1,
showGoodsInfo,
copyBtn,
preViewImg,
hanlevedio,
hanletop,
shareLink,
login,
DownTime,
UpTime,
DownTime1,
creatShare,
getTimeIng,
remindUser,
remindAction,
getPhoneNumber,
getRemindTempId,
receiveScoreShare,
copyScoreCase,
preventD
}
},
async onLoad(options) {
// await this.$onLaunched
this.role = uni.getStorageSync('role')
let scenne = uni.getEnterOptionsSync().scene
if (options) {
Object.keys(options).map((key) => {
if (key == 'id') {
this.id = options[key] || 0
} else if (key == 'from') {
this.sale_id = options[key] || 0
} else if (key == 's') {
this.s = options[key] || 0
} else if (key == 'u') {
this.u = options[key] || 0
} else if (key == 'company_id') {
this.company_id = options[key] || ''
}
})
} else {
this.id = options.id
this.sale_id = options.from || 0
this.s = options.s || 0
this.u = options.u || 0
}
this.pay_id = options.pay_id || ''
if (options.scene) {
const scene = decodeURIComponent(options.scene)
this.id = scene.split(',')[0] || 0
this.sale_id = scene.split(',')[1] || 0
this.s = scene.split(',')[2] || 0
this.u = scene.split(',')[3] || 0
}
await this.getlist()
this.Color = uni.getStorageSync('theme_color')
this.Theme = uni.getStorageSync('theme_index') * 1
this.priceColor = Style[uni.getStorageSync('theme_index') * 1].priceColor
this.tagColor = Style[uni.getStorageSync('theme_index') * 1].tagColor
if(this.pay_id && scenne === 1008) {
this.receiveScoreShare()
}
let params = {
from: this.sale_id,
s: this.s,
u: this.u,
group_id: this.id,
scene: scenne,
company_id: this.company_id
}
this.userBind(params)
await this.getcomment()
await this.getmerchantId()
await this.getBoxtitle()
await this.getshare()
await this.getTop()
await this.getProduct()
await this.getCartList()
this.getShareUrl()
this.source = options.source || ''
// this.getRemindTempId()
if(!uni.getStorageSync('shop_id')) {
this.getShopInfo()
}
},
onShow() {
// uni.onCopyUrl((result) => {
// let sharlink = this.shareUrl.split('?')[1]
// return {
// query: sharlink
// }
// })
},
onReachBottom() {
if (this.page < this.lastPage) {
this.page++
this.getTop()
}
},
onPageScroll(e) {
if (e.scrollTop > 200) {
this.color = true
this.show_top = true
} else {
this.color = false
this.show_top = false
}
},
onShareAppMessage() {
return {
title: this.tableList.title,
imageUrl: this.Url_image,
path: this.shareUrl
}
}
}
</script>
<style lang="scss" scoped>
.flex{
display: flex;
align-items: center;
justify-content: center;
}
.titles {
font-size: 32rpx;
line-height: 60rpx;
margin: 0rpx 0rpx 0rpx 40rpx;
padding-top: 10rpx;
}
.point {
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: v-bind('Color');
float: left;
margin: 0 50rpx;
vertical-align: middle;
position: absolute;
left: 0;
top: 50%;
}
.paragraph {
line-height: 50rpx;
font-weight: bold;
position: relative;
}
.titl {
margin-left: 80rpx;
}
.goods_info {
font-size: 24rpx;
padding: 0 40rpx;
}
.introduction {
background: #fff;
margin-top: -8rpx;
font-size: 28rpx;
padding-bottom: 20rpx;
line-height: 45rpx;
}
.car_active1 {
border: 1px solid #aaa !important;
color: #aaa !important;
}
.car_active {
opacity: 0.6;
}
.top{
position: fixed;
bottom: 15%;
right: 5%;
text-align: center;
z-index: 99;
.top_noe{
background: #fff;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-bottom: 20rpx;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
}
.top_two{
background: v-bind('Color');
width: 80rpx;
height: 80rpx;
border-radius: 50%;
}
}
.goods_param{
padding: 20rpx 40rpx;
background: #fff;
margin: 20rpx 0;
.tit{
font-size: 28rpx;
color: #2c2c2c;
}
.content{
font-size: 24rpx;
color: #555;
margin-top: 10rpx;
line-height: 40rpx;
}
}
.edition_box {
margin: 8rpx 0;
position: relative;
&.big{
margin: 0;
}
.image{
vertical-align: bottom;
}
.background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1;
image {
width: 30px;
height: 30px;
}
}
.img {
width: 100%;
}
.small_img {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.imgs {
width: 32.3%;
height: 200rpx;
margin: 20rpx 0;
image {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.imgs:nth-child(2) {
margin: 20rpx 10rpx;
}
.imgs:nth-child(5) {
margin: 20rpx 10rpx;
}
.imgs:nth-child(8) {
margin: 20rpx 10rpx;
}
}
.text {
line-height: 55rpx;
font-size: 30rpx;
color: #222;
}
}
.sale-goods {
padding: 30rpx 30rpx 0;
position: relative;
&-item {
padding-bottom: 100rpx;
max-height: 65vh;
overflow: auto;
}
.tit {
font-size: 34rpx;
text-align: center;
height: auto;
font-weight: 600;
padding-bottom: 30rpx;
}
.price,
.item {
padding: 10rpx 0;
font-size: 28rpx;
}
.item {
.copy {
border: 1rpx solid #d3d3d3;
border-radius: 50rpx;
padding: 0 15rpx;
margin-left: 20rpx;
}
}
.price {
.commission {
color: v-bind('Color');
}
.sku {
margin-top: 10rpx;
}
}
.btnbox{
width: 100%;
padding: 0 30rpx;
position: absolute;
left: 0;
bottom: 10rpx;
box-sizing: border-box;
.btn{
height: 86rpx;
width: 100%;
background-color: v-bind('Color');
color: #fff;
font-size: 30rpx;
border-radius: 49rpx;
}
}
}
.recommend{
.box_tite{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 0 20rpx;
.hezi{
width: 48.5%;
margin-bottom: 24rpx;
background: #fff;
border-radius: 10rpx;
.icon{
font-size: 26rpx;
}
}
image{
width: 100%;
height: 343rpx;
vertical-align: bottom;
border-radius: 10rpx 10rpx 0 0;
}
.tit{
padding: 0 20rpx;
margin: 20rpx 0 10rpx;
font-size: 28rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-break: break-all;
}
.number{
padding: 0 20rpx 20rpx;
color: v-bind('priceColor');
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
}
.edition{
padding: 0 30rpx;
padding-top: 30rpx;
word-wrap: break-word;
background: #fff;
}
.market_price {
display: inline-block;
margin-left: 10rpx;
color: #676767;
text-decoration: line-through;
font-size: 25rpx;
}
.box_zong{
margin-top: 20rpx;
display: flex;
flex-wrap: wrap;
.box_imgs {
width: 33.3%;
image {
width: 200rpx;
height: 200rpx;
margin-bottom: 30rpx;
}
}
}
.huaxin {
display: inline-block;
margin-left: 20rpx;
color: #676767;
text-decoration: line-through;
font-size: 30rpx;
}
.foot {
position: fixed;
bottom: 0;
width: 100%;
background: #ffffff;
box-shadow: 0rpx 3rpx 20rpx rgba(0, 0, 0, 0.16);
box-sizing: border-box;
z-index: 99;
.tite {
background: #fef9e3;
text-align: center;
padding: 15rpx 30rpx;
font-size: 27rpx;
}
.foot_list {
display: flex;
align-items: center;
padding: 20rpx 0;
}
.foot_noe {
width: 40%;
display: flex;
justify-content: space-around;
.noe {
font-size: 25rpx;
display: flex;
flex-direction: column;
position: relative;
.shuliang {
font-size: 20rpx;
position: absolute;
top: -12rpx;
left: 100%;
margin-left: -26rpx;
color: #fff;
background: v-bind('tagColor');
line-height: 1;
text-align: center;
border-radius: 20rpx;
padding: 4rpx 6rpx;
}
}
}
.remind{
flex-direction: column;
height: 80rpx;
border-radius: 80rpx;
background: #32C55A;
color: #fff;
width: 58%;
&.disabled{
opacity: 0.7;
}
.topone{
font-size: 28rpx;
}
.bot{
display: flex;
align-items: center;
color: #fff;
font-size: 22rpx;
}
}
.foot_two {
display: flex;
justify-content: space-around;
align-items: center;
flex: 1;
font-size: 28rpx;
.group {
width: 204rpx;
height: 70rpx;
background: v-bind('Color');
color: #fff;
border-radius: 70rpx;
}
.car {
width: 204rpx;
height: 70rpx;
border: 1px solid v-bind('Color');
color: v-bind('Color');
border-radius: 70rpx;
box-sizing: border-box;
}
}
}
.goods-box {
background-color: #fff !important;
}
.goods-comment {
background: #fff;
padding: 20rpx 30rpx;
box-sizing: border-box;
margin-bottom: 20rpx;
margin-top: 20rpx;
.goodslist {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
.goodsbox {
display: flex;
align-items: center;
width: calc(100% - 240rpx);
.tit{
width: calc(100% - 104rpx);
}
image {
width: 84rpx;
height: 84rpx;
margin-right: 20rpx;
border-radius: 10rpx;
}
}
}
.goodscommodity {
display: flex;
margin-top: 30rpx;
overflow: auto;
.goodsgun {
box-sizing: border-box;
overflow: hidden;
flex-shrink: 0;
width: 33%;
image {
width: 214rpx;
height: 214rpx;
}
.title_list {
font-size: 26rpx;
font-family: Source Han Sans CN;
font-weight: 400;
color: #2c2c2c;
margin: 10rpx 0;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.price_list {
font-size: 34rpx;
font-family: Source Han Sans CN;
font-weight: 400;
color: v-bind('priceColor');
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
.icon {
font-size: 24rpx;
}
}
}
}
}
.commentBox{
background-color: #fff;
margin-top: 20rpx;
padding: 0 30rpx 10rpx;
.toptitle{
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #fafafa;
padding: 24rpx 0;
.num{
font-size: 30rpx;
font-weight: bold;
}
.more{
font-size: 28rpx;
}
}
.commentlist{
.item{
margin-top: 30rpx;
.itemtop{
display: flex;
justify-content: space-between;
.user{
display: flex;
flex: 1;
.avatar{
width: 70rpx;
height: 70rpx;
border-radius: 50%;
margin-right: 12rpx;
}
.right{
font-size: 24rpx;
flex: 1;
.time{
color: #98989f;
}
}
}
.date{
font-size: 24rpx;
color: #999;
white-space: nowrap;
line-height: 70rpx;
}
}
.text{
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
white-space: break-spaces;
margin-top: 16rpx;
font-size: 28rpx;
}
.rate{
display: flex;
align-items: center;
margin-top: 5px;
.star{
margin-right: 3px;
}
}
}
}
}
.SKU {
display: flex;
background: #fff;
padding: 20rpx 30rpx;
box-sizing: border-box;
color: #676767;
.sku_list {
flex: 1;
display: flex;
justify-content: space-between;
font-size: 26rpx;
color: #333;
.name {
flex: 1;
}
}
}
.title {
background: #fff;
display: flex;
justify-content: space-between;
padding: 20rpx 30rpx;
box-sizing: border-box;
margin-bottom: 20rpx;
.price {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 90%;
.szie {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
white-space: wrap;
}
.color {
color: v-bind('priceColor');
position: relative;
margin-top: 40px;
.font {
display: inline-block;
font-size: 26rpx;
font-weight: bolder;
text{
font-size: 40rpx;
}
}
.move_endTime {
color: #666666;
position: absolute;
right: -76rpx;
top: 12rpx;
font-size: 22rpx;
.sfm-warp {
display: inline-block;
width: 35rpx;
height: 35rpx;
line-height: 35rpx;
background-color: #222;
color: #ffffff;
box-sizing: border-box;
text-align: center;
border-radius: 10rpx;
}
.sfm-warp1 {
margin-left: 15rpx;
}
}
}
.move_img {
display: inline-block;
width: 25%;
font-size: 24rpx;
color: #fff;
margin: 3px 0px;
background-image: url('@/static/image/move_img.png');
background-repeat: no-repeat;
padding: 0px 3px 0px 12px;
height: 40rpx;
background-size: 100% 100%;
line-height: 40rpx;
}
}
.share {
font-size: 25rpx;
display: flex;
flex-direction: column;
}
}
.goods-bar {
position: fixed;
top: 0;
width: 100%;
z-index: 100;
height: 90rpx;
align-items: center;
display: flex;
.icon {
width: 60rpx;
height: 60rpx;
background-color: rgba(255, 255, 255, 0.7);
border-radius: 50%;
}
}
.home-top-swiper {
width: 100%;
height: 750rpx;
.item_img {
width: 100%;
height: 100%;
}
}
.popup {
padding-bottom: 20rpx;
.cancel {
width: 690rpx;
height: 86rpx;
line-height: 86rpx;
background: v-bind('Color');
border-radius: 49rpx;
text-align: center;
color: #fff;
margin: 0 auto;
}
}
.shipbox{
font-size: 26rpx;
color: #333;
padding: 6rpx 30rpx 20rpx;
border-radius: 10px;
background-color: #fff;
box-sizing: border-box;
width: 100%;
display: flex;
justify-content: space-between;
.row{
display: flex;
padding: 8rpx 0;
font-weight: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: calc(100% - 60rpx);
text{
font-weight: 600;
}
}
}
.caseBox{
padding: 40rpx;
box-sizing: border-box;
.tit{
font-size: 30rpx;
color: #000;
font-weight: 600;
padding: 40rpx;
text-align: center;
}
.copycase{
height: 80rpx;
width: 100%;
border-radius: 8rpx;
background: v-bind('Color');
font-size: 26rpx;
color: #fff;
}
.title1{
font-size: 30rpx;
color: #000;
font-weight: 600;
padding: 20rpx 0 40rpx;
text-align: center;
}
.num{
text-align: center;
font-size: 28rpx;
padding-bottom: 40rpx;
text{
color: v-bind('Color');
font-weight: 600;
font-size: 36rpx;
}
}
}
</style>