123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843 |
- <template>
- <view :style="themeColor()">
- <view class="bg-[var(--page-bg-color)] min-h-[100vh] relative" v-if="Object.keys(goodsDetail).length">
- <!-- 自定义头部 -->
- <view class="flex items-center fixed left-0 right-0 z-10 bg-transparent detail-head" :class="{'!bg-[#fff]' :detailHeadBgChange}" :style="navbarInnerStyle">
- <text class="nc-iconfont nc-icon-zuoV6xx" :style="navbarInnerArrowStyle" @click="goback()"></text>
- <view class="ml-auto !pt-[12rpx] !pb-[8rpx] px-[10rpx] bg-[rgba(255,255,255,.4)] rounded-full border-[2rpx] border-solid border-transparent box-border nc-iconfont nc-icon-fenxiangV6xx font-bold text-[#303133] text-[36rpx]" :class="{'border-[#d8d8d8]': detailHeadBgChange}" @click="openShareFn"></view>
- </view>
- <view class="swiper-box">
- <u-swiper :list="goodsDetail.goods.goods_image" :indicator="goodsDetail.goods.goods_image.length" :indicatorStyle="{'bottom': '50rpx'}" :autoplay="true" height="100vw" radius="0" @click="swiperClick"></u-swiper>
- </view>
- <view v-if="priceType == 'discount_price'" class="rounded-t-[40rpx] -mt-[36rpx] relative flex items-center justify-between !bg-cover box-border pb-[26rpx] h-[136rpx] px-[30rpx]" :style="{ background: 'url(' + img('addon/mall/detail/discount_price_bg.png') + ') no-repeat'}">
- <view class="text-[#fff]">
- <text class="text-[28rpx] mr-[10rpx] font-500">折扣价</text>
- <view class="inline-block">
- <text class="text-[32rpx] price-font mr-[4rpx]">¥</text>
- <text class="text-[56rpx] -mb-[4rpx] price-font">{{ parseFloat(goodsPrice).toFixed(2).split('.')[0] }}</text>
- <text class="text-[32rpx] price-font">.{{ parseFloat(goodsPrice).toFixed(2).split('.')[1] }}</text>
- </view>
- <text class="text-[32rpx] ml-[14rpx] line-through price-font" v-if="goodsDetail.market_price && parseFloat(goodsDetail.market_price)">
- ¥{{ goodsDetail.market_price }}
- </text>
- </view>
- <view class="flex flex-col text-[#fff] items-end">
- <image class="h-[28rpx] mr-[2rpx]" :src="img('addon/mall/detail/discount_price.png')" mode="heightFix"></image>
- <view class="flex items-center text-[24rpx] -mb-[10rpx]">
- <text class="mr-[4rpx]">距结束</text>
- <up-count-down class="!text-[#fff] text-[28rpx]" :time="discountTime" format="HH:mm:ss"></up-count-down>
- </view>
- </view>
- </view>
- <view class="bg-[var(--page-bg-color)] rounded-[40rpx] overflow-hidden -mt-[28rpx] relative">
- <view class="datail-title relative px-[30rpx]" :class="{'pt-[40rpx]': priceType == 'discount_price','pt-[20rpx]': priceType != 'discount_price'}">
- <view class="text-[var(--price-text-color)] flex items-baseline mb-[12rpx]" v-if="priceType != 'discount_price'">
- <view class="inline-block">
- <text class="text-[32rpx] font-500 price-font">¥</text>
- <text class="text-[48rpx] font-500 price-font">{{ parseFloat(goodsPrice).toFixed(2).split('.')[0] }}</text>
- <text class="text-[32rpx] font-500 mr-[10rpx] price-font">.{{ parseFloat(goodsPrice).toFixed(2).split('.')[1] }}</text>
- </view>
- <image v-if="priceType == 'member_price'" class="h-[34rpx] mr-[12rpx] w-[80rpx]" :src="img('addon/mall/VIP.png')" mode="heightFix" />
- <text class="text-[26rpx] text-[var(--text-color-light9)] line-through price-font" v-if="goodsDetail.market_price && parseFloat(goodsDetail.market_price)">
- ¥{{ goodsDetail.market_price }}
- </text>
- </view>
- <view class="text-[#333] font-500 text-[30rpx] multi-hidden leading-[40rpx]">
- {{ goodsDetail.goods.goods_name }}
- </view>
- <view class="flex items-start mt-[24rpx]">
- <view class="flex flex-wrap" v-if="goodsDetail.label_info && goodsDetail.label_info.length">
- <view v-for="item in goodsDetail.label_info" :key="item.label_id"
- class="tag-item text-[#FA6400] mb-[10rpx] h-[36rpx] text-[20rpx] px-[12rpx] border-[2rpx] border-solid border-[#FA6400] mr-[15rpx] truncate">
- {{ item.label_name }}
- </view>
- </view>
- <view class="text-[22rpx] mb-[10rpx] text-[var(--text-color-light9)] flex items-baseline ml-auto">
- <text class="whitespace-nowrap">销量</text>
- <text class="mx-[2rpx]">{{ goodsDetail.goods.sale_num }}</text>
- <text>{{ goodsDetail.goods.unit }}</text>
- </view>
- </view>
- </view>
- </view>
- <view class="mt-[var(--top-m)] sidebar-marign card-template" v-if="isGoodsPropertyTemp">
- <view @click="servicesDataShow = !servicesDataShow" v-if="goodsDetail.service && goodsDetail.service.length" class="card-template-item">
- <text class="text-[#333] text-[26rpx] leading-[30rpx] font-400 flex-shrink-0">服务</text>
- <view class="text-[#343434] text-[26rpx] leading-[30rpx] font-400 truncate ml-auto">
- {{ goodsDetail.service[0].service_name }}
- </view>
- <text class="nc-iconfont nc-icon-youV6xx text-[26rpx] text-[var(--text-color-light6)] ml-[8rpx]"></text>
- </view>
- <view @click="buyFn" v-if="goodsDetail.goodsSpec && goodsDetail.goodsSpec.length" class="card-template-item">
- <text class="text-[#333] text-[26rpx] leading-[30rpx] font-400 flex-shrink-0 mr-[20rpx]">已选</text>
- <view class="ml-auto text-right truncate flex-1 text-[#343434] text-[26rpx] leading-[30rpx] font-400">
- {{ goodsDetail.sku_spec_format }}
- </view>
- <text class="nc-iconfont nc-icon-youV6xx text-[26rpx] text-[var(--text-color-light6)] ml-[8rpx]"></text>
- </view>
- <view class="card-template-item" @click="distributionDataOpen" v-if="goodsDetail.goods.goods_type == 'real'&&goodsDetail.delivery_type_list&&goodsDetail.delivery_type_list.length" >
- <text class="text-[#333] text-[26rpx] leading-[30rpx] font-400 flex-shrink-0">配送</text>
- <view class="ml-auto flex items-center text-[#343434] text-[26rpx] leading-[30rpx] font-400">
- {{goodsDetail.delivery_type_list[selectDeliveryType]}}
- </view>
- <text class="nc-iconfont nc-icon-youV6xx text-[26rpx] text-[var(--text-color-light6)] ml-[8rpx]"></text>
- </view>
- <view @click="couponListShow = true" v-if="couponList.length" class="card-template-item">
- <text class="text-[#333] text-[26rpx] leading-[30rpx] font-400 flex-shrink-0 mr-[20rpx]">领券</text>
- <view class="ml-auto flex-1 flex-nowrap flex items-center overflow-hidden h-[44rpx] content-between">
- <block v-for="(item, index) in couponList" :key="index">
- <text v-if="index < 3" class="tag-item whitespace-nowrap border-[2rpx] px-[6rpx] h-[40rpx] border-solid border-[var(--primary-color)] text-[var(--primary-color)] mt-[4rpx]" :class="{'mr-[12rpx]': couponList.length != (index+1) && index < 2, 'ml-auto': index == 0}">
- {{ item.title }}
- </text>
- </block>
- </view>
- <text class="nc-iconfont nc-icon-youV6xx text-[26rpx] text-[var(--text-color-light6)] ml-[8rpx]"></text>
- </view>
- </view>
- <view class="mt-[var(--top-m)] sidebar-marign card-template">
- <view class="flex justify-between items-center">
- <view class="flex flex-1">
- <u--image class="rounded-[6rpx] overflow-hidden" width="86rpx" height="86rpx" :src="img( goodsDetail.shop_info.icon? goodsDetail.shop_info.icon : '')" model="aspectFill">
- <template #error>
- <image :src="img('addon/mall/shop/shop_default.png')" class="w-[86rpx] h-[86rpx]"></image>
- </template>
- </u--image>
- <view class="ml-[20rpx] flex flex-col justify-center">
- <view class="flex items-center">
- <text class="text-[28rpx] text-[#282828] font-600 leading-[38rpx] max-w-[200rpx] truncate">{{goodsDetail.shop_info.site_name}}</text>
- <text class="ml-[8rpx] bg-[var(--primary-color)] text-[#fff] text-[20rpx] rounded-[4rpx] px-[4rpx] leading-[28rpx]" v-if="goodsDetail.shop_info.is_self">{{goodsDetail.shop_info.is_self ? '自营' : ''}}</text>
- </view>
- <view class="text-[22rpx] text-[var(--text-color-light6)] mt-[8rpx] leading-[30rpx]">{{goodsDetail.shop_info.follow_number}}人关注</view>
- </view>
- </view>
- <view class="w-[114rpx] h-[50rpx] leading-[50rpx] bg-[var(--primary-color)] text-[#fff] text-center rounded-[25rpx] text-[28rpx]" @click="toShopDetail(goodsDetail.shop_info.site_id)">进店</view>
- </view>
- </view>
- <view class="mt-[var(--top-m)] sidebar-marign card-template">
- <view class="flex items-center justify-between min-h-[40rpx]" :class="{'mb-[30rpx]': evaluate && evaluate.list && evaluate.list.length}">
- <text class="title">宝贝评价({{ evaluate.count }})</text>
- <view v-if="evaluate.count" class="h-[40rpx] flex items-center" @click="toLink(goodsDetail.goods_id)">
- <text class="text-[24rpx] text-[var(--text-color-light9)]">查看全部</text>
- <text class="nc-iconfont nc-icon-youV6xx text-[26rpx] text-[var(--text-color-light9)]"></text>
- </view>
- <text v-if="!evaluate.count" class="text-[24rpx] text-[var(--text-color-light9)]">暂无评价</text>
- </view>
- <view>
- <view :class="{'pb-[30rpx]': index != (evaluate.list.length-1)}" v-for="(item, index) in evaluate.list" :key="index">
- <view class="flex items-center w-full">
- <u-avatar :default-url="img('static/resource/images/default_headimg.png')" :src="img(item.member_head)" :size="'50rpx'" leftIcon="none"></u-avatar>
- <text class="ml-[10rpx] text-[28rpx] text-[#333]">{{ item.member_name }}</text>
- </view>
- <view class="flex justify-between w-full mt-[16rpx]">
- <view class="flex-1 w-[540rpx] text-[26rpx] text-[#333] max-h-[72rpx] leading-[36rpx] multi-hidden mr-[50rpx]">{{ item.content }}</view>
- </view>
- <view class="w-[80rpx] flex-shrink-0">
- <u--image v-if="item.image_mid && item.image_mid.length" width="80rpx" height="80rpx" radius="16rpx" :src="img(item.image_mid[0])" mode="aspectFill" @click="imgListPreview(item.images[0])">
- <template #error>
- <u-icon name="photo" color="#999" size="50"></u-icon>
- </template>
- </u--image>
- </view>
- </view>
- </view>
- </view>
- <view class="my-[var(--top-m)] goods-sku sidebar-marign card-template" v-if="goodsDetail.goods && goodsDetail.goods.attr_format && Object.keys(goodsDetail.goods.attr_format).length">
- <view class="title mb-[30rpx]">商品属性</view>
- <view>
- <block v-for="(item,index) in goodsDetail.goods.attr_format" :key="index">
- <view v-if="index < 4 || isAttrFormatShow" class="card-template-item">
- <view class="text-[26rpx] leading-[30rpx] w-[160rpx] font-400 shrink-0 text-[var(--text-color-light9)]">{{item.attr_value_name}}</view>
- <view class="text-[#333] box-border value-wid text-[26rpx] leading-[30rpx] font-400 truncate pl-[20rpx]">{{Array.isArray(item.attr_child_value_name) ? item.attr_child_value_name.join(',') : item.attr_child_value_name }}</view>
- </view>
- </block>
- <view v-if="goodsDetail.goods.attr_format.length > 4" class="flex items-center justify-center" @click="isAttrFormatShow = !isAttrFormatShow">
- <text class="text-[24rpx] mr-[10rpx] text-[var(--text-color-light9)]">{{!isAttrFormatShow ? '展开' : '收起'}}</text>
- <text class="nc-iconfont !text-[22rpx] text-[var(--text-color-light9)]" :class="{'nc-icon-xiaV6xx': !isAttrFormatShow, 'nc-icon-shangV6xx-1': isAttrFormatShow}"></text>
- </view>
- </view>
- </view>
- <view class="my-[var(--top-m)] sidebar-marign card-template px-[var(--pad-sidebar-m)]">
- <view class="title pb-[30rpx]">商品详情</view>
- <view class="u-content">
- <u-parse :content="goodsDetail.goods.goods_desc" :tagStyle="{img: 'vertical-align: top;',p:'overflow: hidden;word-break:break-word;' }"></u-parse>
- </view>
- </view>
-
- <!-- tabber -->
- <view class="tab-bar-placeholder"></view>
- <view class="border-[0] border-t-[2rpx] border-solid border-[#f5f5f5] w-[100%] flex justify-between pl-[32rpx] pr-[4rpx] bg-[#fff] box-border fixed left-0 bottom-0 tab-bar z-1 items-center">
- <view class="flex items-center">
- <view class="flex flex-col justify-center items-center mr-[38rpx]" @click="redirect({ url: '/app/pages/index/index', mode: 'reLaunch' })">
- <view class="nc-iconfont nc-icon-shouyeV6xx text-[36rpx]"></view>
- <text class="text-[20rpx] mt-[10rpx]">首页</text>
- </view>
- <view class="flex flex-col justify-center items-center mr-[38rpx]" @click="openShareFn">
- <view class="nc-iconfont nc-icon-fenxiangV6xx text-[36rpx]"></view>
- <text class="text-[20rpx] mt-[10rpx]">分享</text>
- </view>
- <view class="flex flex-col justify-center items-center mr-[38rpx]" @click="collectFn">
- <text class="nc-iconfont text-[36rpx]" :class="{'text-[#ff0000] nc-icon-xihuanV6mm': isCollect, 'text-[#303133] nc-icon-guanzhuV6xx' : !isCollect}"></text>
- <text class="text-[20rpx] mt-[10rpx]">收藏</text>
- </view>
- </view>
- <view class="flex flex-1" v-if="goodsDetail.goods.status == 1">
- <button v-if="goodsDetail.goods.goods_type == 'real' || (goodsDetail.goods.goods_type == 'virtual' && goodsDetail.goods.virtual_receive_type != 'verify')"
- class="flex-1 !h-[70rpx] font-500 text-[26rpx] !text-[#fff] !m-0 !mr-[16rpx] leading-[70rpx] rounded-full remove-border"
- style="background: linear-gradient(127deg, #FFB000 0%, #FFA029 100%);" @click="buyFn('join_cart')">
- 加入购物车</button>
- <button
- v-if="isShowSingleSku"
- :style="{ width : (goodsDetail.goods.goods_type == 'real' || (goodsDetail.goods.goods_type == 'virtual' && goodsDetail.goods.virtual_receive_type != 'verify')) ? '200rpx' : '420rpx' + '!important' }"
- class="flex-1 !h-[70rpx] font-500 text-[26rpx] !text-[#fff] primary-btn-bg !m-0 !mr-[16rpx] leading-[70rpx] rounded-full remove-border"
- @click="buyFn('buy_now')">立即购买</button>
- <button
- v-else :style="{ width : (goodsDetail.goods.goods_type == 'real' || (goodsDetail.goods.goods_type == 'virtual' && goodsDetail.goods.virtual_receive_type != 'verify')) ? '200rpx' : '420rpx' + '!important' }"
- class="flex-1 !h-[70rpx] font-500 text-[26rpx] !text-[#fff] !bg-[#ccc] !m-0 !mr-[16rpx] leading-[70rpx] rounded-full remove-border"
- >已售罄</button>
- </view>
- <view class="flex flex-1" v-else>
- <button class="w-[100%] !h-[70rpx] font-500 text-[26rpx] !text-[#fff] !bg-[#ccc] !m-0 leading-[70rpx] rounded-full remove-border">该商品已下架</button>
- </view>
- </view>
- <!-- 服务 -->
- <view @touchmove.prevent.stop>
- <u-popup class="popup-type" :show="servicesDataShow" @close="servicesDataShow = false">
- <view class="min-h-[480rpx]" @touchmove.prevent.stop>
- <view class="flex items-center justify-center py-[34rpx] relative">
- <text class="text-[32rpx] leading-[36rpx] font-500">商品服务</text>
- </view>
- <scroll-view class="h-[520rpx]" scroll-y="true">
- <view class="pl-[22rpx] py-[28rpx] pr-[37rpx]">
- <view class="flex mb-[28rpx]" v-for="(item, index) in goodsDetail.service">
- <image class="mt-[4rpx] w-[32rpx] h-[32rpx] mr-[14rpx]" :src="img(item.image || 'addon/mall/icon_service.png')" mode="aspectFit" />
- <view class="flex-1">
- <view class="text-[30rpx] leading-[36rpx] text-[#333] mb-[8rpx]">{{ item.service_name }}</view>
- <view class="text-[24rpx] leading-[36rpx] text-[var(--text-color-light9)]">{{ item.desc }}</view>
- </view>
- </view>
- </view>
- </scroll-view>
- </view>
- </u-popup>
- </view>
- <!-- 配送 -->
- <view @touchmove.prevent.stop>
- <u-popup class="popup-type" :show="distributionDataShow" @close="distributionDataShow = false">
- <view class="min-h-[360rpx]" @touchmove.prevent.stop>
- <view class="flex items-center justify-center py-[34rpx] relative">
- <text class="text-[32rpx] leading-[36rpx] font-500">配送方式</text>
- </view>
- <scroll-view class="h-[520rpx]" scroll-y="true">
- <view class="px-[var(--popup-sidebar-m)] pt-[28rpx]">
- <view class="flex mb-[40rpx]" v-for="(item, index) in goodsDetail.delivery_type_list" @click="distributionListFn(item,index)">
- <image class="mt-[4rpx] w-[32rpx] h-[32rpx] mr-[14rpx]" :src="img('addon/mall/icon_service.png')" mode="aspectFit" />
- <view class="flex-1">
- <view class="text-[30rpx] leading-[36rpx] text-[#333] mb-[8rpx]">{{ item }}</view>
- <view class="text-[24rpx] leading-[36rpx] text-[var(--text-color-light9)]">{{ item }}</view>
- </view>
- </view>
- </view>
- </scroll-view>
- </view>
- </u-popup>
- </view>
- <!-- 优惠券 -->
- <view @touchmove.prevent.stop>
- <u-popup class="popup-type" :show="couponListShow" @close="couponListShow = false">
- <view class="min-h-[480rpx]" @touchmove.prevent.stop>
- <view class="flex items-center justify-center py-[34rpx] relative">
- <text class="text-[32rpx] leading-[36rpx] font-500">优惠券</text>
- </view>
- <scroll-view class="h-[520rpx]" :scroll-y="true">
- <view class="px-[32rpx]">
- <view
- class="mb-[30rpx] flex items-center border-[2rpx] border-solid border-[rgba(0,0,0,.1)] rounded-[var(--rounded-small)]"
- v-for="(item, index) in couponList" :key="index">
- <view
- class="flex flex-col items-center my-[20rpx] w-[200rpx] border-0 border-r-[2rpx] border-dashed border-[rgba(0,0,0,.1)]">
- <view class="text-xs price-font">
- <text class="text-[28rpx]">¥</text>
- <text class="text-[48rpx]">{{ item.price }}</text>
- </view>
- <text class="text-xs mt-[12rpx]">{{ Number(item.min_condition_money) ? ('满' + item.min_condition_money + '元可用') : '无门槛' }}</text>
- </view>
- <view class="ml-[20rpx] flex-1 flex flex-col py-[20rpx]">
- <text class="text-xs font-500">{{ item.title }}</text>
- <text class="text-xs text-[var(--text-color-light6)] mt-[12rpx]">{{ item.valid_type == 1 &&
- ('领取之日起' + item.length + '天内有效') || item.valid_type == 2 &&
- ('领取之日起至' + item.valid_end_time) }}</text>
- </view>
- <text v-if="item.btnType === 'collecting'"
- class="bg-[var(--primary-color)] mr-[20rpx] w-[106rpx] box-border text-center text-[#fff] h-[50rpx] text-[22rpx] px-[20rpx] leading-[50rpx] rounded-[100rpx]"
- @click="getCouponFn(item, index)">领取</text>
- <text v-else
- class="!bg-[#FFB4B1] mr-[20rpx] text-[#fff] mr-[20rpx] h-[50rpx] text-[22rpx] px-[20rpx] leading-[50rpx] rounded-[100rpx]">{{
- item.btnType
- === 'collected' ? '已领完' : '已领取' }}</text>
- </view>
- </view>
- </scroll-view>
- <view class="px-[20rpx] pb-[32rpx] pt-[42rpx]">
- <button
- class="font-500 !w-[100%] !h-[80rpx] primary-btn-bg text-[28rpx] !text-[#fff] !m-0 rounded-full leading-[80rpx]"
- @click="couponListShow = false">确定</button>
- </view>
- </view>
- </u-popup>
- </view>
- <ns-goods-sku ref="goodsSkuRef" :goods-detail="goodsDetail" @change="specSelectFn"></ns-goods-sku>
- <share-poster ref="sharePosterRef" posterType="shop_goods" :posterId="goodsDetail.goods.poster_id" :posterParam="posterParam" :copyUrlParam="copyUrlParam" />
- </view>
- <u-loading-page bg-color="rgb(248,248,248)" :loading="loading" loadingText=""></u-loading-page>
- <!-- #ifdef MP-WEIXIN -->
- <!-- 小程序隐私协议 -->
- <wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
- <!-- #endif -->
- <!-- 强制绑定手机号 -->
- <bind-mobile ref="bindMobileRef" />
- </view>
- </template>
- <script setup lang="ts">
- import { ref, computed, getCurrentInstance, nextTick } from 'vue';
- import { onLoad, onShow,onUnload, onPageScroll } from '@dcloudio/uni-app'
- import { img, redirect, handleOnloadParams,getToken, deepClone} from '@/utils/common';
- import { t } from '@/locale';
- import { getGoodsDetail, collect, cancelCollect, getEvaluateList, addGoodsBrowse } from '@/addon/mall/api/goods';
- import { getMallGoodsCoupon, getCoupon } from '@/addon/mall/api/coupon';
- import nsGoodsSku from '@/addon/mall/components/ns-goods-sku/ns-goods-sku.vue';
- import bindMobile from '@/components/bind-mobile/bind-mobile.vue';
- import useCartStore from '@/addon/mall/stores/cart'
- import { useLogin } from '@/hooks/useLogin'
- import useMemberStore from '@/stores/member'
- import { useShare }from '@/hooks/useShare'
- import sharePoster from '@/components/share-poster/share-poster.vue'
- // 分享
- const{setShare} = useShare()
- // 会员信息
- const memberStore = useMemberStore()
- const userInfo = computed(() => memberStore.info)
- // 购物车数量
- const cartStore = useCartStore();
- let cartTotalNum = computed(() => cartStore.totalNum)
- let goodsSkuRef = ref(null);
- let goodsDetail = ref({});
- let isAttrFormatShow = ref(false); //控制属性是否展开
- let loading = ref<boolean>(false);
- let servicesDataShow = ref<boolean>(false)
- let distributionDataShow = ref<boolean>(false) //配送
- let couponListShow = ref<boolean>(false) //优惠券
- let discountTime = ref(0)
- const sendMessageTitle = ref('')
- const sendMessagePath = ref('')
- const sendMessageImg = ref('')
- onLoad((option) => {
- // #ifdef MP-WEIXIN
- // 处理小程序场景值参数
- option = handleOnloadParams(option);
- // #endif
- getGoodsDetail({
- goods_id: option.goods_id || '',
- sku_id: option.sku_id || '',
- }).then(res => {
- if (!res.data.goods || JSON.stringify(res.data) === '[]') {
- uni.showToast({ title: '找不到该商品', icon: 'none' })
- setTimeout(() => {
- redirect({ url: '/app/pages/index/index', mode: 'reLaunch' })
- }, 600)
- return false
- }
- goodsDetail.value = deepClone(res.data);
- isCollect.value = goodsDetail.value.goods.is_collect;
- goodsDetail.value.delivery_type_list = goodsDetail.value.goods.delivery_type_list ? Object.values(goodsDetail.value.goods.delivery_type_list).map(el => el.name) : [];
- goodsDetail.value.goods.goods_image = goodsDetail.value.goods.goods_image_thumb_big;
- goodsDetail.value.goods.goods_image.forEach((item, index) => {
- goodsDetail.value.goods.goods_image[index] = img(item);
- })
- // 商品属性
- if(goodsDetail.value.goods.attr_format){
- goodsDetail.value.goods.attr_format = goodsDetail.value.goods.attr_format.filter((item, index) => {
- return Array.isArray(item.attr_child_value_name) ? item.attr_child_value_name.length : item.attr_child_value_name
- })
- }
-
- sendMessageTitle.value = goodsDetail.value.goods.goods_name
- sendMessagePath.value = '/addon/mall/pages/goods/detail?sku_id=' + goodsDetail.value.sku_id;
- sendMessageImg.value = img(goodsDetail.value.goods.goods_cover_thumb_mid)
- // 分享 - start
- if(res.data.goods){
- let share = {
- title: goodsDetail.value.goods.goods_name,
- desc: goodsDetail.value.goods.sub_title,
- url: goodsDetail.value.goods.goods_cover_thumb_mid
- }
- uni. setNavigationBarTitle({
- title: goodsDetail.value.goods.goods_name
- })
- setShare({
- wechat:{
- ...share
- },
- weapp:{
- ...share
- }
- });
- }
- // 分享 - end
- // 折扣信息
- if(Object.keys(goodsDetail.value.goods).length && goodsDetail.value.goods.is_discount && Object.keys(goodsDetail.value.discount_info).length){
- let now = new Date();
- let timestamp = now.getTime();
- discountTime.value = goodsDetail.value.discount_info.active.end_time*1000 - timestamp.toFixed(0)
- }
- // 获取优惠券列表
- getMallCouponListFn();
- // 获取评价
- getEvaluateListFn();
-
- copyUrlFn();
- addGoodsBrowseFn();
- nextTick(() => {
- setTimeout(()=>{
- const query = uni.createSelectorQuery().in(instance);
- query.select('.swiper-box').boundingClientRect(data => {
- swiperHeight = data ? data.height : 0;
- }).exec();
- query.select('.detail-head').boundingClientRect(data => {
- if(data) {
- detailHead = data.height ? data.height : 0;
- }
- }).exec();
- }, 400)
- })
- })
- })
- onShow(() => {
- // 删除配送方式
- uni.removeStorageSync('distributionType');
- cartStore.getList();
- })
- const specSelectFn = (id) => {
- goodsDetail.value.skuList.forEach((item, index) => {
- if (item.sku_id == id) {
- Object.assign(goodsDetail.value, item);
- }
- })
- }
- // 判断单规格库存是否为0
- const isShowSingleSku = computed(() => {
- let isSingleSpec = false // 是否为单规格,true:多规格,false:单规格
- goodsDetail.value.skuList.forEach((item,index)=>{
- if(item.sku_spec_format){
- isSingleSpec = true
- }
- })
- // 单规格,库存为0,显示已售罄
- if(!isSingleSpec && goodsDetail.value.stock <= 0){
- return false;
- }else if(!isSingleSpec && goodsDetail.value.stock > 0){
- // 单规格,库存大于0,可以购买
- return true;
- }
- return true;
- })
- // 判断商品属性模块是否展示
- const isGoodsPropertyTemp = computed(() => {
- let bool = false;
- if(goodsDetail.value.service && goodsDetail.value.service.length ||
- goodsDetail.value.goodsSpec && goodsDetail.value.goodsSpec.length ||
- goodsDetail.value.goods.goods_type == 'real'&&goodsDetail.value.delivery_type_list&&goodsDetail.value.delivery_type_list.length ||
- couponList.value.length){
- bool = true;
- }
- return bool;
- })
- const buyFn = (type) => {
- goodsSkuRef.value.open(type)
- }
- //强制绑定手机号
- const bindMobileRef = ref(null)
- // 收藏
- let isCollect = ref(0);
- const collectFn = () => {
- // 检测是否登录
- if (!userInfo.value) {
- useLogin().setLoginBack({ url: '/addon/mall/pages/goods/detail', param: { sku_id: goodsDetail.value.sku_id } })
- return false
- }
- // 绑定手机号
- if(uni.getStorageSync('isbindmobile')){
- bindMobileRef.value.open()
- return false
- }
- let api = isCollect.value ? cancelCollect(goodsDetail.value.goods_id) : collect(goodsDetail.value.goods_id);
- api.then(res => {
- isCollect.value = !isCollect.value;
- if (isCollect.value) {
- uni.showToast({
- title: '收藏成功',
- icon: 'none'
- });
- } else {
- uni.showToast({
- title: '取消收藏',
- icon: 'none'
- });
- }
- })
- }
- // 优惠券
- let couponList = ref([]);
- const getMallCouponListFn = () => {
- getMallGoodsCoupon({
- site_id: goodsDetail.value.shop_info.site_id,
- category_id: goodsDetail.value.goods.goods_category || '',
- mall_category_id: goodsDetail.value.goods.goods_mall_category || '',
- goods_id: goodsDetail.value.goods_id || '',
- brand_id: goodsDetail.value.goods.brand_id || ''
- }).then(res => {
- couponList.value = res.data.data.map((el: any) => {
- if (!userInfo.value) {
- if (el.sum_count != -1 && el.receive_count === el.sum_count) {
- el.btnType = 'collected'//已领完
- } else {
- el.btnType = 'collecting'//领用
- }
- } else {
- if (el.is_receive) {
- if (el.member_receive_count < el.limit_count) {
- if (el.need_receive) {
- el.btnType = 'collecting'//领用
- } else {
- el.btnType = 'using'//去使用
- }
- } else {
- if (el.need_receive) {
- el.btnType = 'used'//已使用
- } else {
- el.btnType = 'using'//去使用
- }
- }
- } else {
- if (el.sum_count != -1 && el.receive_count === el.sum_count) {
- el.btnType = 'collected'//已领完
- } else {
- el.btnType = 'collecting'//领用
- }
- }
- }
- return el
- });
- })
- }
- // 领取优惠券
- const getCouponFn = (data, index) => {
- // 检测是否登录
- if (!userInfo.value) {
- useLogin().setLoginBack({ url: '/addon/mall/pages/goods/detail', param: { sku_id: goodsDetail.value.sku_id } })
- return false
- }
- // 绑定手机号
- if(uni.getStorageSync('isbindmobile')){
- bindMobileRef.value.open()
- return false
- }
- getCoupon({
- coupon_id: data.id || '',
- number: 1,
- }).then(res => {
- // couponList.value[index].btnType = 'using'
- getMallCouponListFn();
- })
- }
- // 获取评价
- const evaluate = ref({
- count : 0
- })
- const getEvaluateListFn = () => {
- getEvaluateList(goodsDetail.value.goods_id).then(res => {
- evaluate.value = res.data
- })
- }
- //进入评论
- const toLink = () => {
- redirect({ url: '/addon/mall/pages/evaluate/list', param: { goods_id: goodsDetail.value.goods_id } })
- }
- //浏览记录
- const addGoodsBrowseFn = () => {
- if (userInfo.value && userInfo.value.member_id) {
- addGoodsBrowse({goods_id:goodsDetail.value.goods_id,sku_id:goodsDetail.value.sku_id}).then(res => {})
- }
- }
- //进入店铺
- const toShopDetail = (site_id) => {
- redirect({ url: '/app/pages/site/index', param: { site_id } })
- }
- //预览图片
- const imgListPreview = (item:any,index:any) => {
- if(Array.isArray(item)){
- if (!item.length) return false
- var urlList =item;
- uni.previewImage({
- indicator: "number",
- current:index,
- loop: true,
- urls: urlList
- })
- }else{
- if (item === '') return false
- var urlList = []
- urlList.push(img(item)) //push中的参数为 :src="item.img_url" 中的图片地址
- uni.previewImage({
- indicator: "number",
- loop: true,
- urls: urlList
- })
- }
-
- }
- // 返回上一页
- const goback=()=> {
- if(getCurrentPages().length > 1){
- uni.navigateBack({
- delta: 1
- });
- }else{
- redirect({
- url: '/app/pages/index/index',
- mode: 'reLaunch'
- });
- }
- }
- /************ 选择配送方式-start ****************/
- const selectDeliveryType = ref(0);
- const distributionDataOpen = (()=>{
- distributionDataShow.value = true;
- });
- const distributionListFn = ((data,index)=>{
- selectDeliveryType.value = index;
- distributionDataShow.value = false;
- uni.setStorageSync('distributionType', data);
- });
- /************ 选择配送方式-end ****************/
- /************ 自定义头部-start ****************/
- // 获取系统状态栏的高度
- let systemInfo = uni.getSystemInfoSync();
- let platform = systemInfo.platform;
- let menuButtonInfo = {};
- // 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
- // #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
- menuButtonInfo = uni.getMenuButtonBoundingClientRect();
- // #endif
- // 导航栏内部盒子的样式
- const navbarInnerStyle = computed(() => {
- let style = '';
- // 导航栏宽度,如果在小程序下,导航栏宽度为胶囊的左边到屏幕左边的距离
- // #ifdef MP
- let rightButtonWidth = menuButtonInfo.width ? menuButtonInfo.width * 2 + 'rpx' : '70rpx';
- style += 'height:' + menuButtonInfo.height + 'px;';
- style += 'padding-right:calc(' + rightButtonWidth + ' + 30rpx);';
- style += 'padding-left:calc(' + rightButtonWidth + ' + 30rpx);';
- style += 'padding-top:' + menuButtonInfo.top + 'px;';
- style += 'padding-bottom: 8px;';
-
- style += 'font-size: 32rpx;';
- if (platform === 'ios') {
- // 苹果(iOS)设备
- style += 'font-weight: 500;';
- } else if (platform === 'android') {
- // 安卓(Android)设备
- style += 'font-size: 36rpx;';
- }
- // #endif
-
- // #ifdef H5
- style += 'height: 100rpx;';
- style += 'padding-right: 30rpx;';
- style += 'padding-left: 30rpx;';
-
- style += 'font-size: 32rpx;';
- if (platform === 'ios') {
- // 苹果(iOS)设备
- style += 'font-weight: 500;';
- } else if (platform === 'android') {
- // 安卓(Android)设备
- style += 'font-size: 36rpx;';
- }
- // #endif
- return style;
- })
- // 导航栏内部盒子的样式
- const navbarInnerArrowStyle = computed(() => {
- let style = '';
- // 导航栏宽度,如果在小程序下,导航栏宽度为胶囊的左边到屏幕左边的距离
- // #ifdef MP
- style += "padding-left: 10rpx;"
- style += "padding-right: 10rpx;"
- style += 'position: absolute;';
- style += 'left:calc( 100vw - ' + menuButtonInfo.right + 'px);';
- style += 'font-size: 26px;';
- if (platform === 'ios') {
- // 苹果(iOS)设备
- style += 'font-weight: 700;';
- } else if (platform === 'android') {
- // 安卓(Android)设备
-
- }
- // #endif
- // #ifdef H5
- style += 'font-size: 26px;';
- // #endif
- return style;
- })
- // 头部滚动
- const instance = getCurrentInstance();
- let swiperHeight = 0
- let detailHead = 0
- let detailHeadBgChange = ref(false)
- onPageScroll((e)=>{
- if (swiperHeight == 0 || detailHead == 0) return;
- let height = swiperHeight - detailHead - 20;
- detailHeadBgChange.value = false;
- if (e.scrollTop >= height) {
- detailHeadBgChange.value = true;
- }
- })
- /************ 自定义头部-end ****************/
- const swiperClick = (index)=>{
- if(typeof index == 'number')
- imgListPreview(goodsDetail.value.goods.goods_image,index)
- }
- /************* 分享海报-start **************/
- let sharePosterRef = ref(null);
- let copyUrlParam = ref('');
- let posterParam = {};
- // 分享海报链接
- const copyUrlFn = ()=>{
- copyUrlParam.value = '?sku_id='+goodsDetail.value.sku_id;
- if (userInfo.value && userInfo.value.member_id) copyUrlParam.value += '&mid=' + userInfo.value.member_id;
- }
- const openShareFn = ()=>{
- posterParam.sku_id = goodsDetail.value.sku_id;
- if (userInfo.value && userInfo.value.member_id) posterParam.member_id = userInfo.value.member_id;
- sharePosterRef.value.openShare()
-
- }
- /************* 分享海报-end **************/
- // 价格类型
- let priceType = ref('') //''=>原价,discount_price=>折扣价,member_price=>会员价
- // 商品价格
- let goodsPrice = computed(() =>{
- let price = "0.00";
- if(Object.keys(goodsDetail.value).length && Object.keys(goodsDetail.value.goods).length && goodsDetail.value.goods.is_discount && goodsDetail.value.sale_price != goodsDetail.value.price){
- // 折扣价
- price = goodsDetail.value.sale_price ? goodsDetail.value.sale_price : goodsDetail.value.price;
- priceType.value = 'discount_price'
- }else if(Object.keys(goodsDetail.value).length && Object.keys(goodsDetail.value.goods).length && goodsDetail.value.goods.member_discount && getToken() && goodsDetail.value.member_price != goodsDetail.value.price){
- // 会员价
- price = goodsDetail.value.member_price ? goodsDetail.value.member_price : goodsDetail.value.price;
- priceType.value = 'member_price'
- }else{
- price = goodsDetail.value.price
- priceType.value = ''
- }
- return price;
- })
- // 关闭预览图片
- onUnload(()=>{
- // #ifdef H5 || APP
- uni.closePreviewImage()
- // #endif
- })
- </script>
- <style lang="scss" scoped>
- .remove-border {
- &::after {
- border: none;
- }
- }
- :deep(.u-cell-group__wrapper) {
- .u-cell__body {
- padding: 23rpx 32rpx;
- }
- }
- .tab-bar-placeholder {
- padding-bottom: calc(constant(safe-area-inset-bottom) + 100rpx);
- padding-bottom: calc(env(safe-area-inset-bottom) + 100rpx);
- }
- .tab-bar {
- padding-top: 16rpx;
- padding-bottom: calc(constant(safe-area-inset-bottom) + 16rpx);
- padding-bottom: calc(env(safe-area-inset-bottom) + 16rpx);
- }
- :deep(.u-count-down) .u-count-down__text{
- color: #fff;
- font-size: 28rpx;
- }
- :deep(.u-swiper-indicator__wrapper--line__bar){
- height: 5rpx !important;
- }
- :deep(.u-swiper-indicator__wrapper--line){
- height: 5rpx !important;
- }
- .datail-title{
- background: linear-gradient(#fff , rgba(255,255,255,0));
- }
- .goods-sku .value-wid{
- width: calc(100% - 160rpx);
- }
- </style>
|