Files
uniapp-im-shop/pages/mall/detail.vue
2026-02-06 01:12:04 +08:00

409 lines
9.9 KiB
Vue

<script setup>
import { onLoad, onShow } from '@dcloudio/uni-app'
import {
getProductDetail,
getProductCommentList,
getParticipateList
} from '@/api/mall'
import { ref, computed } from 'vue'
import { navigateTo, navigateBack } from '@/utils/router'
import { getRemainingTime, parseDateTime } from '../../utils/dateUtils'
const viewData = ref({})
const productId = ref('')
// 分享二维码进入
const groupId = ref('')
/** 评论数量 */
const commentNum = ref(0)
/** 分享弹窗 */
const shareDialog = ref(false)
/** 是否显示拼团数据 */
const isPingTuan = ref(false)
/** 拼团列表 */
const pingtuanList = ref([])
const getData = async productId => {
try {
const res = await getProductDetail(productId)
viewData.value = res.data
if (res.data.groupActivities.length > 0) {
const c = await getParticipateList(res.data.groupActivities[0].id)
console.log(c.data, '====')
console.log(getRemainingTime('2026-01-28 23:46:40'))
pingtuanList.value = c.data.map(v => {
return {
...v,
showDate: true
}
})
isPingTuan.value = c.data.length > 0
} else {
isPingTuan.value = false
}
} catch (error) {
navigateBack()
}
}
/** 评论数量获取 */
const getComment = async productId => {
const res = await getProductCommentList(
{
productId,
pageNum: 1,
pageSize: 1
},
false
)
commentNum.value = res.total
}
/** 拼单人数 */
const getPeople = computed(() => {
if (!viewData.value.groupActivities?.length) return 0
return viewData.value.groupActivities[0].totalPeople
})
const onConfirm = () => {
navigateTo('/pages/mall/confirm-order', {
productId: productId.value,
groupId: groupId.value
})
}
onLoad(async e => {
productId.value = e.productId
groupId.value = e?.groupId || ''
await getData(e.productId)
})
onShow(() => {
getComment(productId.value)
})
</script>
<template>
<view class="mall-detail">
<nav-bar>
<template #back>
<image
src="/static/images/public/return-icon.png"
mode="heightFix"
class="left-icon"
></image>
</template>
<template #right>
<!-- shareDialog = true -->
<!-- navigateTo('/pages/shop-together/user', {
type: 1,
id: currentLive.liveID
}) -->
<image
src="/static/images/public/share-icon.png"
mode="heightFix"
class="right-icon"
@click="shareDialog = true"
></image>
</template>
</nav-bar>
<!-- 顶部图片 -->
<view class="top-img">
<swiper
class="swiper"
circular
indicator-dots
autoplay
:interval="4000"
:duration="500"
>
<swiper-item
v-for="(item, index) in viewData.imageGallery"
:key="index"
>
<image :src="item" mode="scaleToFill" class="img"></image>
</swiper-item>
</swiper>
</view>
<!-- 商品详情 -->
<view class="detail-box">
<text class="title">{{ viewData.productName }}</text>
<view class="price">
<text>¥</text>
<text>{{ viewData.minPrice }}</text>
</view>
<view class="name-box">
<text>拼单数量:{{ viewData.salesCount }}</text>
<text>好评率:99%</text>
</view>
<view v-if="!groupId && isPingTuan" class="ping-box">
<view v-for="(item, index) in pingtuanList" :key="index">
<!-- 拼单量 -->
<view class="line-box">
<view class="left-img">
<text>拼单</text>
<image
:src="`/static/images/public/random${
Math.floor(Math.random() * 7) + 1
}.png`"
mode="scaleToFill"
class="avatar"
></image>
<image
:src="`/static/images/public/random${
Math.floor(Math.random() * 7) + 1
}.png`"
mode="scaleToFill"
class="avatar"
></image>
<image
:src="`/static/images/public/random${
Math.floor(Math.random() * 7) + 1
}.png`"
mode="scaleToFill"
class="avatar"
></image>
</view>
<text class="right-name">
还需{{ item.needPeople }}人拼单
</text>
</view>
<!-- 去拼团 -->
<view class="bottom-name">
<view class="count-down">
<text>距离结束:</text>
<uni-countdown
:day="parseDateTime(item.endTime).day"
:hour="parseDateTime(item.endTime).hour"
:minute="parseDateTime(item.endTime).minute"
:second="parseDateTime(item.endTime).second"
:show-colon="false"
@timeup="
() => {
item.showDate = false
}
"
/>
</view>
<!-- <button
v-if="item.showDate"
@click="
navigateTo('/pages/mall/confirm-order', {
productId: productId,
groupId: item.id
})
"
>
去拼单
</button> -->
</view>
</view>
</view>
<!-- 评论入口 -->
<view
class="comment-box"
@click="navigateTo('/pages/mall/comment', { productId })"
>
<text class="comment-name">评论({{ commentNum }})</text>
<view class="right-box">
<text>查看全部</text>
<image
src="/static/images/public/right-arrow.png"
mode="heightFix"
class="right-img"
></image>
</view>
</view>
<!-- 商品详情 -->
<view class="detail-content">
<text class="title">商品详情</text>
<mp-html
:content="viewData.description"
class="rich-box"
></mp-html>
</view>
</view>
<!-- 底部按钮 -->
<bottom-view>
<cb-button @click="onConfirm">拼单购买</cb-button>
</bottom-view>
<!-- 分享弹窗 -->
<share-popup
v-model:show="shareDialog"
:id="productId"
:text="viewData.productName"
:cover="viewData.mainImage"
:price="viewData.minPrice"
></share-popup>
</view>
</template>
<style lang="scss" scoped>
.ping-box {
max-height: 500rpx;
overflow-y: auto;
}
.left-icon,
.right-icon {
height: 64rpx;
}
.top-img {
position: relative;
&::after {
content: '';
position: absolute;
bottom: -2rpx;
left: 0;
width: 100%;
height: 56rpx;
background: #fff;
border-radius: 32rpx 32rpx 0 0;
}
.swiper {
width: 100%;
height: 628rpx;
}
.img {
width: 100%;
height: 628rpx;
}
}
.detail-box {
padding: 0 58rpx 150rpx;
font-family: PingFang SC, PingFang SC;
font-style: normal;
text-transform: none;
.title {
font-weight: bold;
font-size: 32rpx;
color: #333333;
}
.price {
display: flex;
align-items: baseline;
text {
font-weight: 500;
font-size: 24rpx;
color: #eb1c26;
&:last-child {
font-weight: bold;
font-size: 48rpx;
margin: 16rpx 0 16rpx 8rpx;
}
}
}
.name-box {
text {
font-weight: 500;
font-size: 24rpx;
color: #999999;
&:last-child {
margin-left: 66rpx;
}
}
}
.line-box {
margin: 48rpx 0;
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 500;
font-size: 28rpx;
.left-img {
display: flex;
align-items: center;
.avatar {
width: 64rpx;
height: 64rpx;
border-radius: 64rpx;
margin-left: 16rpx;
}
text {
color: #333333;
}
}
.right-name {
color: #999999;
}
}
.bottom-name {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 500;
.count-down {
display: flex;
flex-direction: column;
text {
font-size: 28rpx;
color: #eb1c26;
&:last-child {
color: #999999;
}
}
}
button {
margin: 0;
width: 252rpx;
height: 64rpx;
border-radius: 64rpx;
line-height: 64rpx;
font-size: 28rpx;
color: #00d993;
border: 2rpx solid #00d993;
background: #ffffff;
&::after {
border: none;
}
}
}
.detail-content {
border-top: 2rpx solid #f9f9f9;
padding-top: 20rpx;
margin-top: 20rpx;
.title {
margin-bottom: 16rpx;
font-weight: 500;
font-size: 28rpx;
color: #333333;
}
.rich-box {
margin-top: 16rpx;
width: 100%;
}
}
.comment-box {
border-top: 2rpx solid #f9f9f9;
padding-top: 20rpx;
margin-top: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-style: normal;
text-transform: none;
.comment-name {
font-size: 28rpx;
color: #333333;
}
.right-box {
display: flex;
align-items: center;
text {
font-size: 28rpx;
color: #999999;
margin-right: 8rpx;
}
.right-img {
height: 32rpx;
}
}
}
}
</style>