698 lines
15 KiB
Vue
698 lines
15 KiB
Vue
<template>
|
||
<layout class="goodsDetail">
|
||
<uv-navbar
|
||
fixed
|
||
:safeAreaInsetTop="true"
|
||
autoBack
|
||
title=""
|
||
bg-color="transparent"
|
||
/>
|
||
<view v-if="detailData">
|
||
<swiper
|
||
class="swiper detail"
|
||
circular
|
||
indicator-dots
|
||
autoplay
|
||
>
|
||
<swiper-item
|
||
v-for="(item, index) in sliderImageData"
|
||
:key="index"
|
||
>
|
||
<view class="swiper-item">
|
||
<image
|
||
class="image"
|
||
:src="item"
|
||
mode="widthFix"
|
||
/>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
</swiper>
|
||
<view class="goodsDetail-info">
|
||
<view class="goodsDetail-price-row">
|
||
<view class="goodsDetail-price goodsDetail-price-primary">
|
||
¥{{ storeInfo.price }}
|
||
</view>
|
||
<view
|
||
class="goodsDetail-price goodsDetail-price-original"
|
||
v-if="storeInfo.otPrice"
|
||
>
|
||
¥{{ storeInfo.otPrice }}
|
||
</view>
|
||
</view>
|
||
<view class="goodsDetail-storeName">{{ storeInfo.storeName }}</view>
|
||
<view class="goodsDetail-info-action">
|
||
<view class="goodsDetail-info-action-tag">
|
||
<!-- <space>
|
||
<uv-tags
|
||
plain
|
||
type="primary"
|
||
text="满100减10"
|
||
></uv-tags>
|
||
<uv-tags
|
||
plain
|
||
type="primary"
|
||
text="满100减10"
|
||
></uv-tags>
|
||
</space> -->
|
||
</view>
|
||
<view
|
||
class="goodsDetail-info-action-desc"
|
||
v-if="storeInfo.stock"
|
||
>
|
||
仅剩{{ storeInfo.stock }}件
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<blank size="15"></blank>
|
||
<view class="y-list min">
|
||
<uv-list border>
|
||
<uv-list-item border>
|
||
<view class="y-list-content">
|
||
<view class="y-list-label">运费:</view>
|
||
<view class="y-list-default">{{ detailData.tempName }}</view>
|
||
</view>
|
||
</uv-list-item>
|
||
</uv-list>
|
||
</view>
|
||
|
||
<view class="y-list min">
|
||
<uv-list border>
|
||
<uv-list-item
|
||
border
|
||
clickable
|
||
show-arrow
|
||
@click="handleOpenSelect('select')"
|
||
>
|
||
<view class="y-list-content">
|
||
<view class="y-list-label">选择:</view>
|
||
<view
|
||
class="y-list-select-placeholder"
|
||
v-if="!storeAttr"
|
||
>请选择商品规格</view>
|
||
<view
|
||
class="y-list-select"
|
||
v-if="storeAttr"
|
||
>{{ storeAttr.sku }}</view>
|
||
</view>
|
||
</uv-list-item>
|
||
</uv-list>
|
||
</view>
|
||
|
||
<view class="card full">
|
||
<view class="card-head">
|
||
<view class="card-title">商品评价({{ detailData.replyCount }})</view>
|
||
<view
|
||
class="card-more"
|
||
@tap="$yrouter.navigateTo({
|
||
url: '/pages/goodsReply/goodsReply', query: {
|
||
id: detailData.storeInfo.id
|
||
}
|
||
})"
|
||
><span>
|
||
查看更多
|
||
</span>
|
||
<uv-icon
|
||
name="arrow-right"
|
||
color="rgb(187, 187, 187)"
|
||
size="10"
|
||
/>
|
||
</view>
|
||
</view>
|
||
<view
|
||
class="card-content"
|
||
v-if="detailData.reply"
|
||
>
|
||
<reply :data="detailData.reply" />
|
||
</view>
|
||
</view>
|
||
|
||
<blank size="15"></blank>
|
||
|
||
|
||
<view class="card full">
|
||
<view class="card-head">
|
||
<view class="card-title">
|
||
商品详情
|
||
</view>
|
||
</view>
|
||
<rich-text
|
||
:nodes="storeInfo.description"
|
||
bindtap="onOpenLink"
|
||
/>
|
||
</view>
|
||
<blank size="15"></blank>
|
||
|
||
<container min>
|
||
<view class="center-title">
|
||
<view class="center-title-line"></view>
|
||
<view class="title">热门推荐</view>
|
||
<view class="center-title-line"></view>
|
||
</view>
|
||
|
||
</container>
|
||
<good-attr-select
|
||
ref="selectAttrPanel"
|
||
:id="storeInfo.id"
|
||
:storeInfo="storeInfo"
|
||
:productAttr="detailData.productAttr"
|
||
:productValue="detailData.productValue"
|
||
@select="handleSelectAttr"
|
||
/>
|
||
|
||
</view>
|
||
|
||
<view
|
||
class="action-bar"
|
||
v-if="detailData"
|
||
>
|
||
<view class="action-icons">
|
||
<view class="action-icons-item">
|
||
<view
|
||
class="action-icon"
|
||
@click="goToShopCart"
|
||
>
|
||
<img
|
||
class="action-icon-img"
|
||
src="@/static/images/icon-kefu.png"
|
||
/>
|
||
<text class="action-icon-label">客服</text>
|
||
</view>
|
||
</view>
|
||
<view class="action-icons-item">
|
||
|
||
<view
|
||
class="action-icon"
|
||
@click="goToShopCart"
|
||
>
|
||
<view class="action-icon-badge">
|
||
<uv-badge
|
||
type="error"
|
||
max="99"
|
||
:value="cardCount"
|
||
></uv-badge>
|
||
</view>
|
||
|
||
<img
|
||
class="action-icon-img"
|
||
src="@/static/images/icon-gouwuche.png"
|
||
/>
|
||
<text class="action-icon-label">购物车</text>
|
||
</view>
|
||
</view>
|
||
<view class="action-icons-item">
|
||
|
||
<view
|
||
class="action-icon"
|
||
@click="handleCollect"
|
||
>
|
||
<img
|
||
v-if="!storeInfo?.userCollect"
|
||
class="action-icon-img"
|
||
src="@/static/images/icon-shouceng.png"
|
||
/>
|
||
<img
|
||
v-if="storeInfo?.userCollect"
|
||
class="action-icon-img"
|
||
src="@/static/images/icon-shouceng-o.png"
|
||
/>
|
||
<text class="action-icon-label">收藏</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="action-btns">
|
||
<uv-button
|
||
type="info"
|
||
text="加入购物车"
|
||
plain
|
||
@click="handleOpenSelect('cart')"
|
||
></uv-button>
|
||
<uv-button
|
||
type="primary"
|
||
text="立即购买"
|
||
@click="handleOpenSelect('buy')"
|
||
></uv-button>
|
||
</view>
|
||
</view>
|
||
|
||
</layout>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
import { getProductDetail, getProductAddCollect, getProductDelCollect } from '@/api/product'
|
||
import { getCartAdd, getCartCount } from '@/api/cart'
|
||
import { switchTab } from '@/utils/router'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import { useGlobalProperties } from '@/hooks';
|
||
|
||
const { $yrouter } = useGlobalProperties()
|
||
|
||
const detailData = ref(null)
|
||
const sliderImageData = ref([])
|
||
const storeInfo = ref(null)
|
||
const actionType = ref(null)
|
||
const storeAttr = ref(null)
|
||
const storeNum = ref(null)
|
||
const cardCount = ref(null)
|
||
|
||
const selectAttrPanel = ref(false)
|
||
|
||
const handleGetDetail = async (id) => {
|
||
try {
|
||
const detail = await getProductDetail(id)
|
||
uni.hideLoading();
|
||
if (detail) {
|
||
detailData.value = detail
|
||
sliderImageData.value = detail.storeInfo.sliderImage.split(',')
|
||
storeInfo.value = detail.storeInfo
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
}
|
||
}
|
||
|
||
|
||
onLoad(({ id }) => {
|
||
uni.showLoading({
|
||
title: '加载中'
|
||
});
|
||
handleGetDetail(id)
|
||
handleGetCartCount(id)
|
||
})
|
||
|
||
const goToShopCart = () => {
|
||
switchTab({
|
||
url: '/pages/shoppingCart/shoppingCart',
|
||
})
|
||
}
|
||
|
||
const handleOpenSelect = (action) => {
|
||
actionType.value = action
|
||
selectAttrPanel.value.open()
|
||
}
|
||
|
||
const handleSelectAttr = (attr) => {
|
||
selectAttrPanel.value.close()
|
||
storeAttr.value = attr.store
|
||
storeNum.value = attr.num
|
||
switch (actionType.value) {
|
||
case 'select':
|
||
|
||
break;
|
||
case 'cart':
|
||
handleCardAdd()
|
||
break;
|
||
case 'buy':
|
||
handleBuy()
|
||
break;
|
||
}
|
||
actionType.value = ''
|
||
}
|
||
|
||
|
||
const handleCardAdd = async () => {
|
||
|
||
let res = await getCartAdd({
|
||
cartNum: storeNum.value,
|
||
productId: storeAttr.value.productId,
|
||
uniqueId: storeAttr.value.unique,
|
||
new: 0
|
||
})
|
||
handleGetCartCount()
|
||
uni.showToast({
|
||
title: '已加入购物车',
|
||
duration: 2000
|
||
});
|
||
}
|
||
|
||
const handleBuy = async () => {
|
||
|
||
uni.showLoading({
|
||
title: '加载中'
|
||
});
|
||
|
||
let res = await getCartAdd({
|
||
cartNum: storeNum.value,
|
||
productId: storeAttr.value.productId,
|
||
uniqueId: storeAttr.value.unique,
|
||
new: 1
|
||
})
|
||
|
||
uni.hideLoading();
|
||
|
||
$yrouter.navigateTo({
|
||
url: '/pages/submitOrder/submitOrder',
|
||
query: {
|
||
cartId: res.cartId
|
||
}
|
||
})
|
||
}
|
||
|
||
const handleCollect = async () => {
|
||
storeInfo.value.userCollect = !storeInfo.value.userCollect
|
||
if (storeInfo.value.userCollect) {
|
||
let res = await getProductAddCollect({
|
||
id: storeInfo.value.id,
|
||
})
|
||
uni.showToast({
|
||
title: '已收藏',
|
||
duration: 2000
|
||
});
|
||
if (!res) {
|
||
|
||
storeInfo.value.userCollect = !storeInfo.value.userCollect
|
||
}
|
||
|
||
} else {
|
||
await getProductDelCollect({
|
||
id: storeInfo.value.id,
|
||
})
|
||
uni.showToast({
|
||
title: '取消收藏',
|
||
duration: 2000
|
||
});
|
||
if (!res) {
|
||
storeInfo.value.userCollect = !storeInfo.value.userCollect
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
const handleGetCartCount = async () => {
|
||
const count = await getCartCount()
|
||
console.log("gxs --> % handleGetCartCount % count:\n", count)
|
||
cardCount.value = count.count
|
||
}
|
||
|
||
</script>
|
||
|
||
<style lang="less">
|
||
.search {
|
||
padding: 0 17px;
|
||
}
|
||
|
||
.logo {
|
||
width: 63px;
|
||
height: 25px;
|
||
|
||
.image {
|
||
width: 63px;
|
||
height: 25px;
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
.swiper {
|
||
width: 100%;
|
||
|
||
.image {
|
||
width: 100%;
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
|
||
.goodsDetail {
|
||
width: 100%;
|
||
|
||
&-storeName {
|
||
line-height: 40rpx;
|
||
font-size: 32rpx;
|
||
color: #333333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
|
||
|
||
&-price {
|
||
|
||
&-row {
|
||
margin-bottom: 17rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.goods-price {}
|
||
}
|
||
|
||
&-primary {
|
||
line-height: 50rpx;
|
||
font-size: 50rpx;
|
||
color: #EE6D46;
|
||
}
|
||
|
||
&-default {
|
||
line-height: 40rpx;
|
||
font-size: 28rpx;
|
||
color: #333333;
|
||
}
|
||
|
||
&-original {
|
||
margin-left: 20rpx;
|
||
line-height: 28rpx;
|
||
font-size: 28rpx;
|
||
color: #999999;
|
||
text-decoration: line-through;
|
||
}
|
||
|
||
}
|
||
|
||
&-info {
|
||
background-color: #fff;
|
||
padding: 30rpx 35rpx;
|
||
// display: flex;
|
||
// align-items: flex-end;
|
||
// justify-content: space-between;
|
||
|
||
&-left {}
|
||
|
||
&-action {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
|
||
&-tags {
|
||
.uv-tags {
|
||
margin-right: 10rpx;
|
||
}
|
||
}
|
||
|
||
&-desc {
|
||
line-height: 28rpx;
|
||
font-size: 20rpx;
|
||
color: #999999;
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
&-image {
|
||
&-img {}
|
||
}
|
||
|
||
&-list {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: row;
|
||
padding: 14rpx;
|
||
|
||
.goods {
|
||
&-thumb {
|
||
margin-bottom: 0;
|
||
width: 220rpx;
|
||
height: 220rpx;
|
||
|
||
&-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
&-content {
|
||
padding-right: 40rpx;
|
||
margin-left: 30rpx;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// .goods {
|
||
// padding: 16rpx 14rpx;
|
||
|
||
// &-header {
|
||
// display: flex;
|
||
// align-items: flex-start;
|
||
// }
|
||
|
||
// &-thumb {
|
||
|
||
// width: 220rpx;
|
||
// height: 220rpx;
|
||
|
||
// &-img {
|
||
// width: 100%;
|
||
// height: 100%;
|
||
// display: block;
|
||
// }
|
||
// }
|
||
|
||
// &-content {
|
||
// margin-top: 24rpx;
|
||
// margin-left: 40rpx;
|
||
// flex: 1
|
||
// }
|
||
|
||
// &-storeName {
|
||
// line-height: 40rpx;
|
||
// font-size: 28rpx;
|
||
// font-weight: 500;
|
||
// color: #333333;
|
||
// margin-bottom: 35rpx;
|
||
// }
|
||
|
||
// &-info {
|
||
// display: flex;
|
||
// align-items: center;
|
||
// justify-content: space-between;
|
||
|
||
// &-left {
|
||
// display: flex;
|
||
// align-items: flex-end;
|
||
|
||
// }
|
||
|
||
// &-action {
|
||
// &-btn {}
|
||
|
||
// &-desc {
|
||
// color: #999999;
|
||
// font-size: 24rpx;
|
||
// line-height: 40rpx;
|
||
// }
|
||
// }
|
||
|
||
// }
|
||
|
||
|
||
// &-price {
|
||
// &-default {
|
||
// line-height: 28rpx;
|
||
// font-size: 20rpx;
|
||
// color: #999999;
|
||
|
||
// }
|
||
|
||
// &-primary {
|
||
// line-height: 42rpx;
|
||
// font-size: 30rpx;
|
||
// font-weight: 500;
|
||
// color: #EE6D46;
|
||
// margin-left: 5rpx;
|
||
// }
|
||
// }
|
||
|
||
|
||
|
||
// &-desc {
|
||
// color: #999999;
|
||
// font-size: 24rpx;
|
||
// line-height: 40rpx;
|
||
// }
|
||
|
||
|
||
// &-model {
|
||
// display: inline-flex;
|
||
// align-items: center;
|
||
// width: auto;
|
||
// height: 40rpx;
|
||
// border: 1px solid #CCCCCC;
|
||
// opacity: 1;
|
||
// border-radius: 0rpx;
|
||
// padding: 0 10rpx;
|
||
|
||
// margin-bottom: 28rpx;
|
||
|
||
// &-label {
|
||
// line-height: 38rpx;
|
||
// font-size: 24rpx;
|
||
// color: #999999;
|
||
// }
|
||
|
||
// &-value {
|
||
// line-height: 38rpx;
|
||
// font-size: 24rpx;
|
||
// color: #333333;
|
||
// margin-right: 10rpx;
|
||
// }
|
||
|
||
// &-action {
|
||
// width: 11rpx;
|
||
// height: 7rpx;
|
||
// }
|
||
// }
|
||
|
||
// &-model-info {
|
||
// display: inline-flex;
|
||
// align-items: center;
|
||
// width: auto;
|
||
// height: 40rpx;
|
||
// opacity: 1;
|
||
// border-radius: 0rpx;
|
||
// margin-bottom: 28rpx;
|
||
|
||
// &-label {
|
||
// line-height: 38rpx;
|
||
// font-size: 24rpx;
|
||
// color: #999999;
|
||
// }
|
||
|
||
// &-value {
|
||
// line-height: 38rpx;
|
||
// font-size: 24rpx;
|
||
// color: #333333;
|
||
// margin-right: 10rpx;
|
||
// }
|
||
|
||
// &-action {
|
||
// width: 11rpx;
|
||
// height: 7rpx;
|
||
// }
|
||
// }
|
||
// }
|
||
}
|
||
|
||
.buy-progress {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
&-info {
|
||
flex: 1;
|
||
|
||
&-desc {
|
||
color: #999999;
|
||
font-size: 24rpx;
|
||
line-height: 32rpx;
|
||
}
|
||
}
|
||
|
||
&-action {
|
||
margin-left: 17rpx;
|
||
}
|
||
}
|
||
|
||
.buy-num {
|
||
|
||
&-info-desc {
|
||
color: #999999;
|
||
font-size: 24rpx;
|
||
line-height: 32rpx;
|
||
}
|
||
}
|
||
</style>
|