519 lines
11 KiB
Plaintext
519 lines
11 KiB
Plaintext
<!-- 消费者端 - 商品详情页 -->
|
||
<template>
|
||
<view class="product-detail-page">
|
||
<!-- 商品图片轮播 -->
|
||
<view class="product-images">
|
||
<swiper class="image-swiper" :indicator-dots="true" :autoplay="false">
|
||
<swiper-item v-for="(image, index) in product.images" :key="index">
|
||
<image :src="image" class="product-image" mode="aspectFit" />
|
||
</swiper-item>
|
||
</swiper>
|
||
<view class="image-indicator">{{ currentImageIndex + 1 }} / {{ product.images.length }}</view>
|
||
</view>
|
||
|
||
<!-- 商品基本信息 -->
|
||
<view class="product-info">
|
||
<view class="price-section">
|
||
<text class="current-price">¥{{ product.price }}</text>
|
||
<text v-if="product.original_price" class="original-price">¥{{ product.original_price }}</text>
|
||
</view>
|
||
<text class="product-name">{{ product.name }}</text>
|
||
<text class="sales-info">已售{{ product.sales }}件 · 库存{{ product.stock }}件</text>
|
||
</view>
|
||
|
||
<!-- 店铺信息 -->
|
||
<view class="shop-info" @click="goToShop">
|
||
<image :src="merchant.shop_logo || '/static/default-shop.png'" class="shop-logo" />
|
||
<view class="shop-details">
|
||
<text class="shop-name">{{ merchant.shop_name }}</text>
|
||
<view class="shop-rating">
|
||
<text class="rating-text">评分: {{ merchant.rating.toFixed(1) }}</text>
|
||
<text class="sales-text">销量: {{ merchant.total_sales }}</text>
|
||
</view>
|
||
</view>
|
||
<text class="enter-shop">进店 ></text>
|
||
</view>
|
||
|
||
<!-- 规格选择 -->
|
||
<view class="spec-section" @click="showSpecModal">
|
||
<text class="spec-title">规格</text>
|
||
<text class="spec-selected">{{ selectedSpec || '请选择规格' }}</text>
|
||
<text class="spec-arrow">></text>
|
||
</view>
|
||
|
||
<!-- 商品详情 -->
|
||
<view class="product-description">
|
||
<view class="section-title">商品详情</view>
|
||
<text class="description-text">{{ product.description || '暂无详细描述' }}</text>
|
||
</view>
|
||
|
||
<!-- 底部操作栏 -->
|
||
<view class="bottom-actions">
|
||
<view class="action-buttons">
|
||
<button class="cart-btn" @click="addToCart">加入购物车</button>
|
||
<button class="buy-btn" @click="buyNow">立即购买</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 规格选择弹窗 -->
|
||
<view v-if="showSpec" class="spec-modal" @click="hideSpecModal">
|
||
<view class="spec-content" @click.stop>
|
||
<view class="spec-header">
|
||
<text class="spec-title">选择规格</text>
|
||
<text class="close-btn" @click="hideSpecModal">×</text>
|
||
</view>
|
||
<view class="spec-list">
|
||
<view v-for="sku in productSkus" :key="sku.id"
|
||
class="spec-item"
|
||
:class="{ active: selectedSkuId === sku.id }"
|
||
@click="selectSku(sku)">
|
||
<text class="spec-name">{{ getSkuSpecText(sku) }}</text>
|
||
<text class="spec-price">¥{{ sku.price }}</text>
|
||
<text class="spec-stock">库存{{ sku.stock }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { ProductType, MerchantType, ProductSkuType } from '@/types/mall-types.uts'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
product: {
|
||
id: '',
|
||
merchant_id: '',
|
||
category_id: '',
|
||
name: '',
|
||
description: '',
|
||
images: [] as Array<string>,
|
||
price: 0,
|
||
original_price: 0,
|
||
stock: 0,
|
||
sales: 0,
|
||
status: 0,
|
||
created_at: ''
|
||
} as ProductType,
|
||
merchant: {
|
||
id: '',
|
||
user_id: '',
|
||
shop_name: '',
|
||
shop_logo: '',
|
||
shop_banner: '',
|
||
shop_description: '',
|
||
contact_name: '',
|
||
contact_phone: '',
|
||
shop_status: 0,
|
||
rating: 0,
|
||
total_sales: 0,
|
||
created_at: ''
|
||
} as MerchantType,
|
||
productSkus: [] as Array<ProductSkuType>,
|
||
currentImageIndex: 0,
|
||
showSpec: false,
|
||
selectedSkuId: '',
|
||
selectedSpec: '',
|
||
quantity: 1
|
||
}
|
||
},
|
||
onLoad(options: any) {
|
||
const productId = options.productId as string
|
||
if (productId) {
|
||
this.loadProductDetail(productId)
|
||
}
|
||
},
|
||
methods: {
|
||
loadProductDetail(productId: string) {
|
||
// 模拟加载商品详情数据
|
||
this.product = {
|
||
id: productId,
|
||
merchant_id: 'merchant_001',
|
||
category_id: 'cat_001',
|
||
name: '精选好物商品',
|
||
description: '这是一个高品质的商品,具有优秀的性能和优美的外观设计。',
|
||
images: [
|
||
'/static/product1.jpg',
|
||
'/static/product2.jpg',
|
||
'/static/product3.jpg'
|
||
],
|
||
price: 199.99,
|
||
original_price: 299.99,
|
||
stock: 100,
|
||
sales: 1256,
|
||
status: 1,
|
||
created_at: '2024-01-15'
|
||
}
|
||
|
||
this.merchant = {
|
||
id: 'merchant_001',
|
||
user_id: 'user_001',
|
||
shop_name: '优质好店',
|
||
shop_logo: '/static/shop-logo.png',
|
||
shop_banner: '/static/shop-banner.png',
|
||
shop_description: '专注品质生活',
|
||
contact_name: '店主小王',
|
||
contact_phone: '13800138000',
|
||
shop_status: 1,
|
||
rating: 4.8,
|
||
total_sales: 15680,
|
||
created_at: '2023-06-01'
|
||
}
|
||
|
||
this.loadProductSkus(productId)
|
||
},
|
||
|
||
loadProductSkus(productId: string) {
|
||
// 模拟加载商品SKU数据
|
||
this.productSkus = [
|
||
{
|
||
id: 'sku_001',
|
||
product_id: productId,
|
||
sku_code: 'SKU001',
|
||
specifications: { color: '红色', size: 'M' },
|
||
price: 199.99,
|
||
stock: 50,
|
||
image_url: '/static/sku1.jpg',
|
||
status: 1
|
||
},
|
||
{
|
||
id: 'sku_002',
|
||
product_id: productId,
|
||
sku_code: 'SKU002',
|
||
specifications: { color: '蓝色', size: 'L' },
|
||
price: 219.99,
|
||
stock: 30,
|
||
image_url: '/static/sku2.jpg',
|
||
status: 1
|
||
}
|
||
]
|
||
},
|
||
|
||
showSpecModal() {
|
||
this.showSpec = true
|
||
},
|
||
|
||
hideSpecModal() {
|
||
this.showSpec = false
|
||
},
|
||
|
||
selectSku(sku: ProductSkuType) {
|
||
this.selectedSkuId = sku.id
|
||
this.selectedSpec = this.getSkuSpecText(sku)
|
||
this.hideSpecModal()
|
||
},
|
||
|
||
getSkuSpecText(sku: ProductSkuType): string {
|
||
if (sku.specifications) {
|
||
const specs: any = sku.specifications
|
||
return Object.keys(specs).map(key => `${key}: ${specs[key]}`).join(', ')
|
||
}
|
||
return sku.sku_code
|
||
},
|
||
|
||
addToCart() {
|
||
if (!this.selectedSkuId) {
|
||
uni.showToast({
|
||
title: '请选择规格',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 模拟添加到购物车
|
||
uni.showToast({
|
||
title: '已添加到购物车',
|
||
icon: 'success'
|
||
})
|
||
},
|
||
|
||
buyNow() {
|
||
if (!this.selectedSkuId) {
|
||
uni.showToast({
|
||
title: '请选择规格',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 跳转到订单确认页
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/order-confirm?productId=${this.product.id}&skuId=${this.selectedSkuId}&quantity=${this.quantity}`
|
||
})
|
||
},
|
||
|
||
goToShop() {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/shop-detail?merchantId=${this.merchant.id}`
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.product-detail-page {
|
||
background-color: #f5f5f5;
|
||
min-height: 100vh;
|
||
padding-bottom: 120rpx;
|
||
}
|
||
|
||
.product-images {
|
||
position: relative;
|
||
height: 750rpx;
|
||
background-color: #fff;
|
||
}
|
||
|
||
.image-swiper {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.product-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.image-indicator {
|
||
position: absolute;
|
||
bottom: 20rpx;
|
||
right: 20rpx;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
color: #fff;
|
||
padding: 10rpx 20rpx;
|
||
border-radius: 20rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.product-info {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.price-section {
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.current-price {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #ff4444;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.original-price {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
text-decoration: line-through;
|
||
}
|
||
|
||
.product-name {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
line-height: 1.4;
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.sales-info {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.shop-info {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.shop-logo {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 10rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.shop-details {
|
||
flex: 1;
|
||
}
|
||
|
||
.shop-name {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.shop-rating {
|
||
display: flex;
|
||
}
|
||
|
||
.rating-text, .sales-text {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-right: 30rpx;
|
||
}
|
||
|
||
.enter-shop {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.spec-section {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.spec-title {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
width: 120rpx;
|
||
}
|
||
|
||
.spec-selected {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.spec-arrow {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.product-description {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.description-text {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.bottom-actions {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: #fff;
|
||
padding: 20rpx 30rpx;
|
||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.action-buttons {
|
||
display: flex;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.cart-btn, .buy-btn {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
border-radius: 40rpx;
|
||
font-size: 28rpx;
|
||
border: none;
|
||
}
|
||
|
||
.cart-btn {
|
||
background-color: #ffa726;
|
||
color: #fff;
|
||
}
|
||
|
||
.buy-btn {
|
||
background-color: #ff4444;
|
||
color: #fff;
|
||
}
|
||
|
||
.spec-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: flex-end;
|
||
z-index: 999;
|
||
}
|
||
|
||
.spec-content {
|
||
background-color: #fff;
|
||
width: 100%;
|
||
max-height: 80vh;
|
||
border-radius: 20rpx 20rpx 0 0;
|
||
padding: 30rpx;
|
||
}
|
||
|
||
.spec-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30rpx;
|
||
padding-bottom: 20rpx;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.spec-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.close-btn {
|
||
font-size: 48rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.spec-list {
|
||
max-height: 60vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.spec-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 25rpx 0;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
}
|
||
|
||
.spec-item.active {
|
||
background-color: #fff3e0;
|
||
}
|
||
|
||
.spec-name {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.spec-price {
|
||
font-size: 26rpx;
|
||
color: #ff4444;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.spec-stock {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
width: 100rpx;
|
||
text-align: right;
|
||
}
|
||
</style>
|