This commit is contained in:
2026-09-29 15:17:13 +08:00
commit 69e6ed8c59
113 changed files with 36564 additions and 0 deletions
+289
View File
@@ -0,0 +1,289 @@
<template>
<view class="product-page">
<view class="page-hero">
<AppNavbar class="page-navbar" title="商品详情"/>
</view>
<view class="product-detail" v-if="product.goodsId">
<view class="gallery card">
<swiper class="swiper" circular autoplay indicator-dots indicator-color="#d8e6ff"
indicator-active-color="#2563eb" v-if="product.files">
<swiper-item v-for="(img, idx) in JSON.parse(product.files)" :key="idx">
<image class="cover" :src="img.url" mode="aspectFill"></image>
</swiper-item>
</swiper>
<!-- <view class="badge rating">评分 {{ product.rating }} / 5</view>-->
</view>
<view class="card block">
<view class="price-row">
<view class="price">¥{{ product.salePrice }}</view>
<view class="origin">¥{{ product.originPrice }}</view>
<view class="coupon" @tap="openCoupon">领券</view>
</view>
<view class="name">{{ product.goodsName }}</view>
<!-- <view class="sell-point">{{ // product.sellPoint }}</view>-->
<!-- <view class="meta">规格:{{ product.specs }} · 厂家:{{ product.vendor }}</view>-->
</view>
<!-- <view class="card block">-->
<!-- <view class="section-title">商品规格</view>-->
<!-- <view class="specs">-->
<!-- <view class="chip" v-for="spec in product.specOptions" :key="spec" :class="{'active': spec === selectedSpec}"-->
<!-- @tap="selectedSpec = spec">{{ spec }}-->
<!-- </view>-->
<!-- </view>-->
<!-- </view>-->
<view class="card block">
<view class="section-title">图文详情</view>
<u-parse :content="product.content"/>
</view>
<!-- <view class="card block">-->
<!-- <view class="section-title">热卖推荐</view>-->
<!-- <view class="recommend" v-for="item in recommends" :key="item.id" @tap="openRecommend(item)">-->
<!-- <view class="rec-name">{{ item.name }}</view>-->
<!-- <view class="rec-meta">{{ item.specs }} · ¥{{ item.price }}</view>-->
<!-- </view>-->
<!-- </view>-->
<view class="action-bar">
<u-icon name="share" label="分享" label-pos="bottom" size="40rpx"/>
<view class="action-group">
<view class="primary-btn" @tap="addCart">加入购物车</view>
<view class="primary-btn buy" @tap="buyNow">立即购买</view>
</view>
</view>
<Login ref="Login" @done="getUserData"/>
</view>
</view>
</template>
<script>
import {goodsInfoReq} from "@/api/goods";
import Login from "@/components/Login.vue";
import {userInfoReq} from "@/api/user";
import {getUserInfo} from "@/util/user";
import {addCartReq} from "@/api/cart";
import AppNavbar from "@/components/AppNavbar.vue";
export default {
components: {Login, AppNavbar},
data() {
return {
product: {},
selectedSpec: '10袋/盒',
recommends: [],
isLoggedIn: false,
}
},
onLoad(options) {
if (options.id) {
this.id = options.id
this.getInfo()
}
},
onShow() {
if (getUserInfo().token) {
this.isLoggedIn = true
this.getUserData()
}
},
methods: {
async getUserData() {
const {data} = await userInfoReq()
this.isLoggedIn = true
},
async getInfo() {
const {data} = await goodsInfoReq(this.id)
this.product = data
},
openCoupon() {
uni.navigateTo({
url: '/packageUser/coupon/index'
})
},
async addCart() {
if (!this.isLoggedIn) return this.$refs.Login.open()
await addCartReq({
goodsId: this.product.goodsId,
num: 1
})
uni.showToast({
title: '已加入购物车',
icon: 'success'
})
},
buyNow() {
const goodsDataList = [{
goodsId: this.product.goodsId,
num: 1
}]
uni.navigateTo({
url: `/pages/order/checkout?goodsDataList=${JSON.stringify(goodsDataList)}`
})
},
openRecommend(item) {
uni.navigateTo({
url: `/pages/product/detail?name=${encodeURIComponent(item.name)}&price=${item.price}&origin=${item.price}`
})
}
}
}
</script>
<style lang="scss" scoped>
.product-page {
min-height: 100vh;
padding: 0 20rpx 100rpx;
background: #f5f5f5;
}
.page-hero {
padding: 30rpx 6rpx 18rpx;
background: url('https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/462bfa04cf0eff8698884c38b9d17519.png') no-repeat
top center / 100% auto;
}
.page-navbar {
padding: 0 6rpx;
}
.product-detail {
padding: 0 6rpx 100rpx;
}
.gallery {
padding: 0;
overflow: hidden;
}
.swiper {
height: 320rpx;
}
.cover {
width: 100%;
height: 320rpx;
}
.rating {
position: absolute;
top: 12rpx;
right: 12rpx;
}
.block {
margin-top: 18rpx;
}
.price-row {
display: flex;
align-items: center;
gap: 12rpx;
}
.price {
color: #ff3b30;
font-size: 36rpx;
font-weight: 800;
}
.origin {
color: #a1aabc;
text-decoration: line-through;
}
.coupon {
color: #ff8354;
background: #fff1e9;
border-radius: 999rpx;
padding: 6rpx 12rpx;
border: 1rpx dashed #ffb08a;
}
.name {
font-size: 34rpx;
font-weight: 800;
color: var(--text-main);
margin: 8rpx 0;
}
.sell-point {
color: #ff3b30;
font-size: 26rpx;
margin-bottom: 8rpx;
}
.meta {
color: var(--text-sub);
}
.specs {
display: flex;
gap: 10rpx;
flex-wrap: wrap;
}
.chip.active {
background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-soft));
color: #fff;
border-color: transparent;
}
.detail-text {
color: var(--text-main);
line-height: 1.6;
}
.recommend {
padding: 12rpx 0;
border-bottom: 1rpx solid #edf1f7;
}
.recommend:last-child {
border-bottom: none;
}
.rec-name {
font-weight: 700;
color: var(--text-main);
}
.rec-meta {
color: var(--text-sub);
font-size: 24rpx;
margin-top: 4rpx;
}
.action-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
gap: 10rpx;
padding: 12rpx 24rpx;
background: #ffffff;
box-shadow: 0 -6rpx 16rpx rgba(31, 111, 232, 0.08);
}
.collect {
color: var(--brand-primary);
font-weight: 700;
}
.action-group {
margin-left: 20rpx;
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
}
.buy {
margin-left: 20rpx;
background: linear-gradient(135deg, #ff8354, #ff9f72);
}
</style>