2025-12-09 22:57:49 +08:00

1593 lines
48 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="detail-page">
<!-- 图片轮播 -->
<view class="image-swiper-wrapper">
<swiper class="image-swiper" :indicator-dots="true" :autoplay="false"
:current="currentImageIndex" @change="onSwiperChange" indicator-color="rgba(0,0,0,0.2)"
indicator-active-color="#9810fa" >
<swiper-item v-for="(image, index) in productImages" :key="index">
<image :src="image" mode="aspectFill" class="swiper-image"></image>
</swiper-item>
</swiper>
<!-- 左右箭头 -->
<!-- <view class="swiper-nav prev" @click="prevImage" v-if="productImages.length > 1">
<text></text>
</view>
<view class="swiper-nav next" @click="nextImage" v-if="productImages.length > 1">
<text></text>
</view> -->
<!-- 分享按钮 -->
<view class="share-btn-top">
<button class="share-btn-inner-top" open-type="share" :data-item="productInfo" @click.stop="currentShareItem = productInfo">
<text class="iconfont icon-zhifeiji1"></text>
</button>
</view>
</view>
<!-- 商品信息 -->
<view class="product-info">
<!-- 标签 -->
<view class="product-tags">
<view class="tag" v-if="productInfo.is_hot_selling">热销</view>
<view class="tag" v-if="productInfo.is_limited">限量</view>
<view class="tag" v-if="productInfo.is_imported">法国进口</view>
</view>
<!-- 商品名称 -->
<view class="product-name-row">
<view class="product-name">{{ productInfo.name || '玫瑰香水盲盒' }}</view>
<view class="like-btn-top" @click="handleLike">
<text v-if="productInfo.is_liked" class="iconfont icon-xin heart-filled"></text>
<text v-else class="iconfont icon-xin1 heart-outline"></text>
</view>
</view>
<!-- <view class="product-sub-title">{{ productInfo.description.sub_title || '玫瑰香水盲盒' }}</view> -->
<!-- 评分和喜欢 -->
<view class="product-rating">
<text class="iconfont icon-xingxing star-icon"></text>
<text class="rating-value">{{ productInfo.rating || 4.8 }}</text>
<text class="rating-text">({{ productInfo.review_count || 234 }}条评价)</text>
<text class="like-text">{{ productInfo.like_count || 567 }}人喜欢</text>
</view>
<!-- 价格 -->
<view class="product-price">
<text class="current-price">¥{{ formatPrice(currentPrice) }}</text>
<text class="original-price" v-if="originalPrice > currentPrice">¥{{ formatPrice(originalPrice)
}}</text>
</view>
<view class="sku-hint" v-if="skuList.length > 1 && !selectedSku">
请选择规格
</view>
<!-- 商品描述 -->
<view class="product-description">
{{ productInfo.description||
'经典玫瑰香调,优雅女神范,持久留香8小时。采用法国进口玫瑰精油,层次丰富,前调清新,中调浓郁,后调温暖。适合日常使用,也是送礼的绝佳选择。' }}
</view>
</view>
<!-- 购买选项弹窗 -->
<view class="purchase-modal" v-if="showPurchaseModal" @click="closePurchaseModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">选择规格</text>
<view class="modal-close" @click="closePurchaseModal">
<text>×</text>
</view>
</view>
<view class="modal-body">
<!-- SKU选择列表 -->
<view class="sku-selection" v-if="skuList && skuList.length > 0">
<view class="sku-title-row">
<text class="sku-section-title">选择规格</text>
</view>
<view class="sku-list">
<view class="sku-item" v-for="(sku, index) in skuList"
:key="sku.sku_id !== undefined ? sku.sku_id : index" :class="{
active: selectedSkuId === (sku.sku_id !== undefined ? sku.sku_id : index),
disabled: sku.quantity !== undefined && sku.quantity === 0
}" @click="selectSku(sku, index)">
<view class="sku-info">
<view class="sku-name">{{ sku.name || sku.sku_name || '默认规格' }}</view>
<view class="sku-price-row">
<text class="sku-price-text">¥{{ formatPrice(sku.price) ||
formatPrice(sku.sku_price) }}</text>
<text class="sku-original-price"
v-if="sku.original_price && sku.original_price > sku.price">
¥{{ formatPrice(sku.original_price) }}
</text>
</view>
<view class="sku-stock" v-if="sku.quantity !== undefined">
库存:{{ sku.quantity }}件
</view>
</view>
<view class="sku-check"
v-if="selectedSkuId === (sku.sku_id !== undefined ? sku.sku_id : index)">
<text class="iconfont icon-gou"></text>
</view>
</view>
</view>
</view>
<!-- 数量选择 -->
<view class="quantity-row">
<text class="quantity-label">购买数量</text>
<view class="quantity-control">
<view class="quantity-btn" @click="decreaseQuantity">-</view>
<view class="quantity-value">{{ quantity }}</view>
<view class="quantity-btn" @click="increaseQuantity">+</view>
</view>
</view>
<view class="stock-info">库存{{ currentStock }}件</view>
<view class="subtotal">小计 ¥{{ formatPrice(subtotal) }}</view>
</view>
<view class="modal-footer">
<view class="modal-btn confirm-btn" @click="confirmPurchase">
{{ purchaseAction === 'cart' ? '加入购物车' : '立即购买' }}
</view>
</view>
</view>
</view>
<!-- 导航标签 -->
<view class="nav-tabs">
<view class="nav-tab" :class="{ active: activeTab === 'detail' }" @click="switchTab('detail')">
商品详情
</view>
<view class="nav-tab" :class="{ active: activeTab === 'spec' }" @click="switchTab('spec')">
规格参数
</view>
<view class="nav-tab" :class="{ active: activeTab === 'review' }" @click="switchTab('review')">
用户评价
</view>
</view>
<!-- 内容区域 -->
<view class="content-section">
<!-- 商品详情 -->
<view class="tab-content" v-if="activeTab === 'detail'">
<!-- <view class="detail-section">
<rich-text :nodes="productInfo.description.details"></rich-text>
</view> -->
<view class="detail-section">
<view class="section-title">香调层次</view>
<view class="fragrance-notes">
<view class="note-item">
<text class="note-label">前调:</text>
<text class="note-content">{{ productInfo.scent_level.top_note || '柠檬、佛手柑、粉红胡椒'
}}</text>
</view>
<view class="note-item">
<text class="note-label">中调:</text>
<text class="note-content">{{ productInfo.scent_level.middle_note || '玫瑰、茉莉、牡丹'
}}</text>
</view>
<view class="note-item">
<text class="note-label">后调:</text>
<text class="note-content">{{ productInfo.scent_level.base_note || '白麝香、雪松、香草'
}}</text>
</view>
</view>
</view>
<view class="detail-section">
<view class="section-title">主要成分</view>
<view class="ingredients">
{{ productInfo.main_ingredient || '法国进口玫瑰精油、天然香精、酒精、去离子水' }}
</view>
</view>
<view class="detail-section">
<view class="section-title">使用方法</view>
<view class="ingredients">
<!-- {{ productInfo.usage_instruction || '常温保存' }} -->
<rich-text :nodes="productInfo.usage_instruction"></rich-text>
</view>
</view>
<view class="detail-section">
<view class="section-title">保存方法</view>
<view class="ingredients">
{{ productInfo.storage_instruction || '喷涂' }}
</view>
</view>
</view>
<!-- 规格参数 -->
<view class="tab-content" v-if="activeTab === 'spec'">
<view class="spec-list">
<view class="spec-item">
<text class="spec-label">品牌:</text>
<text class="spec-value">{{ productInfo.attr.brand }}</text>
</view>
<view class="spec-item">
<text class="spec-label">容量:</text>
<text class="spec-value">{{ productInfo.attr.capacity }}ml</text>
</view>
<view class="spec-item">
<text class="spec-label">香型:</text>
<text class="spec-value">{{ productInfo.attr.fragrance_notes }}</text>
</view>
<view class="spec-item">
<text class="spec-label">持香时间:</text>
<text class="spec-value">{{ productInfo.attr.duration }} 小时</text>
</view>
<view class="spec-item">
<text class="spec-label">产地:</text>
<text class="spec-value">{{ productInfo.attr.origin }}</text>
</view>
</view>
</view>
<!-- 用户评价 -->
<view class="tab-content" v-if="activeTab === 'review'">
<view class="review-list" v-if="reviews.length">
<view class="review-item" v-for="(review, index) in reviews" :key="index">
<view class="review-header">
<view class="review-user-info">
<image class="review-avatar"
:src="review?.user_info?.avatar_url || review?.user_info?.avatar || review.avatar || defaultAvatar"
mode="aspectFill"></image>
<view class="review-user-text">
<view class="review-user">
{{ review?.user_info?.username || review.username || '用户' + (index +
1) }}
</view>
<view class="review-sku">
{{ review.product_info.sku_name }}
<!-- ¥{{ formatPrice(review.product_info.price) }} -->
</view>
</view>
</view>
<view class="review-rating">
<text class="iconfont icon-xingxing" v-for="n in (review.rating || 0)"
:key="n"></text>
</view>
</view>
<view class="review-content">{{ review.comment || review.content || '商品很不错,香味持久,包装精美!' }}
</view>
<view class="review-time">{{ review.created_at || review.time || '' }}</view>
</view>
</view>
<view class="review-empty" v-else-if="!isLoadingReviews">
暂无评价
</view>
<view class="review-loading" v-if="isLoadingReviews">
加载中...
</view>
<view class="load-more-reviews" v-if="hasMoreReviews && !isLoadingReviews" @click="loadMoreReviews">
查看更多评价
</view>
</view>
</view>
<!-- 服务保障 -->
<view class="service-guarantee">
<view class="section-title">服务保障</view>
<view class="guarantee-list">
<view class="guarantee-item">
<view class="guarantee-icon guarantee-icon-1">
<text class="iconfont icon-zhengpinbaozhang"></text>
</view>
<text class="guarantee-text">正品保证</text>
</view>
<view class="guarantee-item">
<view class="guarantee-icon guarantee-icon-2">
<text class="iconfont icon-wuliu"></text>
</view>
<text class="guarantee-text">免费配送</text>
</view>
<view class="guarantee-item">
<view class="guarantee-icon guarantee-icon-3">
<text></text>
</view>
<text class="guarantee-text">7天退换</text>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<view class="bar-btn" @click="goHome">
<text class="iconfont icon-caidan"></text>
<text>首页</text>
</view>
<view class="bar-btn" @click="goToCart">
<text class="iconfont icon-gouwuche"></text>
<text>购物车</text>
<view v-if="cartSelectedCount > 0" class="cart-count">{{ cartSelectedCount }}</view>
</view>
<view class="bar-btn cart-btn" @click="addToCart">加入购物车</view>
<!-- <view class="bar-btn primary" @click="buyNow">立即购买</view> -->
</view>
</view>
</template>
<script>
import request from '@/api/request.js';
import { parseDescription } from '/tools/format';
export default {
data() {
return {
productId: '',
currentImageIndex: 0,
productImages: [
'https://via.placeholder.com/750x750/87CEEB/FFFFFF?text=Product+Image+1'
],
productInfo: {
name: '玫瑰香水盲盒',
rating: 4.8,
review_count: 234,
like_count: 567,
price: 139,
original_price: 199,
description: '经典玫瑰香调,优雅女神范,持久留香8小时。采用法国进口玫瑰精油,层次丰富,前调清新,中调浓郁,后调温暖。适合日常使用,也是送礼的绝佳选择。',
is_hot_selling: true,
is_limited: true,
is_imported: true,
quantity: 15,
ingredients: '法国进口玫瑰精油、天然香精、酒精、去离子水',
usage_instruction: '常温保存',
storage_instruction: '喷涂',
scent_level: {
top_note: '柠檬、佛手柑、粉红胡椒',
middle_note: '玫瑰、茉莉、牡丹',
base_note: '白麝香、雪松、香草'
},
attr: {
brand: '香水有毒',
capacity: '50ml',
fragrance_notes: '玫瑰花香调',
duration: '8小时',
origin: '法国'
}
},
skuList: [],
selectedSkuId: null,
selectedSku: null,
quantity: 1,
activeTab: 'detail',
showPurchaseModal: false,
purchaseAction: 'cart', // 'cart' 或 'buy'
cartSelectedCount: 0,
currentShareItem: null,
fragranceNotes: {
top: '柠檬、佛手柑、粉红胡椒',
middle: '玫瑰、茉莉、牡丹',
base: '白麝香、雪松、香草'
},
specifications: [
{ label: '品牌', value: '香水有毒' },
{ label: '容量', value: '50ml' },
{ label: '香型', value: '玫瑰花香调' },
{ label: '适用人群', value: '女性' },
{ label: '保质期', value: '36个月' },
{ label: '产地', value: '法国' }
],
reviews: [],
reviewPage: 1,
reviewPageSize: 5,
reviewsTotal: 0,
isLoadingReviews: false,
// 用户评价默认头像
defaultAvatar: 'https://via.placeholder.com/120x120/eeeeee/999999?text=U'
};
},
computed: {
currentPrice() {
// 优先使用已选SKU价格未选择时回退到列表首项/商品价
const sku = this.selectedSku
|| (this.skuList && this.skuList.length > 0 ? this.skuList[0] : null);
if (sku) {
return sku.price || sku.sku_price || 0;
}
return this.productInfo.price || 139;
},
originalPrice() {
// 直接取第一个SKU的原价
if (this.skuList && this.skuList.length > 0) {
const firstSku = this.skuList[0];
return firstSku.original_price || 0;
}
return this.productInfo.original_price || 199;
},
currentStock() {
if (this.selectedSku && this.selectedSku.quantity !== undefined) {
return this.selectedSku.quantity;
}
return this.productInfo.quantity || 0;
},
subtotal() {
return this.currentPrice * this.quantity;
},
hasMoreReviews() {
return this.reviews.length < this.reviewsTotal;
}
},
onLoad(options) {
this.productId = options.id;
this.loadProductDetail(this.productId);
this.fetchCartSelectedCount();
},
onShow() {
this.fetchCartSelectedCount();
},
// 微信小程序分享
onShareAppMessage(res) {
const item = this.currentShareItem || (res.target && res.target.dataset && res.target.dataset.item) || this.productInfo || {};
return {
title: item.name || '香氛团购',
imageUrl: item.main_image_url || (this.productImages && this.productImages[0]) || '/static/images/home/icon-1.png',
path: item.id ? `/pages/shopDetail/index?id=${item.id}` : '/pages/index/index'
};
},
methods: {
// 格式化价格
formatPrice(value) {
if (!value) {
return 0.00;
}
// 分转换为元
value = value / 100;
// 保留两位小数
return value.toFixed(2);
},
// 加载商品详情
async loadProductDetail(productId) {
const productInfo = await request('xcx/product/' + productId, 'GET');
if (!productInfo) {
console.warn('商品信息为空');
return;
}
this.productInfo = productInfo;
if (productInfo.image_url) {
this.productImages = productInfo.image_url.split(',').filter(url => url.trim());
}
this.productInfo.scent_level = JSON.parse(productInfo.scent_level);
this.productInfo.attr = JSON.parse(productInfo.attr);
// this.productInfo.description = parseDescription(productInfo.description);
// console.log(this.productInfo.description)
// 处理SKU列表
if (productInfo.skus && Array.isArray(productInfo.skus) && productInfo.skus.length > 0) {
this.skuList = productInfo.skus;
// 默认选择第一个有库存的SKU
const availableSku = productInfo.skus.find(sku => sku && (sku.quantity > 0 || sku.quantity === undefined)) || productInfo.skus[0];
if (availableSku) {
const skuIndex = productInfo.skus.indexOf(availableSku);
this.selectSku(availableSku, skuIndex >= 0 ? skuIndex : 0);
}
} else if (productInfo.sku) {
// 如果只有一个SKU对象
this.skuList = [productInfo.sku];
this.selectSku(productInfo.sku, 0);
} else {
// 如果没有SKU使用商品本身作为默认SKU
this.skuList = [{
id: productInfo.id,
name: '默认规格',
price: productInfo.price,
original_price: productInfo.original_price,
quantity: productInfo.quantity
}];
this.selectSku(this.skuList[0], 0);
}
this.fetchProductReviews(true);
},
// 轮播图切换
onSwiperChange(e) {
this.currentImageIndex = e.detail.current;
},
// 上一张图片
prevImage() {
if (this.currentImageIndex > 0) {
this.currentImageIndex--;
} else {
this.currentImageIndex = this.productImages.length - 1;
}
},
// 下一张图片
nextImage() {
if (this.currentImageIndex < this.productImages.length - 1) {
this.currentImageIndex++;
} else {
this.currentImageIndex = 0;
}
},
// 减少数量
decreaseQuantity() {
if (this.quantity > 1) {
this.quantity--;
} else {
uni.showToast({
title: '商品数量不能少于1',
icon: 'none'
});
}
},
// 增加数量
increaseQuantity() {
if (this.quantity < this.currentStock) {
this.quantity++;
} else {
uni.showToast({
title: '库存不足',
icon: 'none'
});
}
},
// 选择SKU
selectSku(sku, index) {
if (!sku) {
return;
}
// 检查库存quantity为0时不可选但undefined时允许选择
if (sku.quantity !== undefined && sku.quantity === 0) {
uni.showToast({
title: '该规格暂无库存',
icon: 'none'
});
return;
}
this.selectedSkuId = sku.sku_id !== undefined ? sku.sku_id : index;
this.selectedSku = sku;
// 如果当前数量超过新SKU的库存重置数量
if (sku.quantity !== undefined && this.quantity > sku.quantity) {
this.quantity = sku.quantity;
}
},
// 切换标签
switchTab(tab) {
this.activeTab = tab;
},
async userIsLogin() {
const token = await uni.getStorageSync('access_token')
if (token) {
return
} else {
uni.navigateTo({
url: '/pages/login/index'
})
}
},
// 收藏/取消收藏
async handleLike() {
await this.userIsLogin().then((res) => {
request('xcx/product/like', 'post', {
product_id: this.productInfo.id || this.productId,
type: this.productInfo.is_liked ? 2 : 1
}).then((res) => {
const liked = !this.productInfo.is_liked
this.productInfo.is_liked = liked
if (liked) {
this.productInfo.like_count = (this.productInfo.like_count || 0) + 1
} else if (this.productInfo.like_count > 0) {
this.productInfo.like_count -= 1
}
}).catch((error) => {
console.error('收藏操作失败:', error)
})
}).catch((err) => {
console.log(err)
})
},
// 打开购买弹窗 - 加入购物车
async addToCart() {
await this.userIsLogin().then(async (res) => {
this.purchaseAction = 'cart';
// 如果还没有选择SKU自动选择第一个可用的
if (!this.selectedSku && this.skuList.length > 0) {
const availableSku = this.skuList.find(sku => sku && (sku.quantity > 0 || sku.quantity === undefined)) || this.skuList[0];
if (availableSku) {
const skuIndex = this.skuList.indexOf(availableSku);
this.selectSku(availableSku, skuIndex >= 0 ? skuIndex : 0);
}
}
this.showPurchaseModal = true;
}).catch((err) => {
console.log(err);
});
},
// 打开购买弹窗 - 立即购买
async buyNow() {
await this.userIsLogin().then((res) => {
this.purchaseAction = 'buy';
// 如果还没有选择SKU自动选择第一个可用的
if (!this.selectedSku && this.skuList.length > 0) {
const availableSku = this.skuList.find(sku => sku && (sku.quantity > 0 || sku.quantity === undefined)) || this.skuList[0];
if (availableSku) {
const skuIndex = this.skuList.indexOf(availableSku);
this.selectSku(availableSku, skuIndex >= 0 ? skuIndex : 0);
}
}
this.showPurchaseModal = true;
}).catch((err) => {
console.log(err);
});
},
// 关闭购买弹窗
closePurchaseModal() {
this.showPurchaseModal = false;
},
// 确认购买
async confirmPurchase() {
if (!this.selectedSku) {
uni.showToast({
title: '请选择商品规格',
icon: 'none'
});
return;
}
if (this.purchaseAction === 'cart') {
// 添加到购物车
try {
await request('xcx/cart', 'POST', {
product_id: this.productInfo.id || this.productId,
sku_id: this.selectedSku.sku_id,
quantity: this.quantity
});
this.showPurchaseModal = false;
uni.showToast({
title: '已添加到购物车',
icon: 'success'
});
this.fetchCartSelectedCount();
} catch (error) {
console.error('添加到购物车失败:', error);
uni.showToast({
title: '添加失败,请重试',
icon: 'none'
});
}
} else {
// 立即购买
this.showPurchaseModal = false;
const orderData = [{
product_id: this.productInfo.id || this.productId,
sku_id: this.selectedSku.sku_id,
quantity: this.quantity,
price: this.currentPrice
}];
uni.navigateTo({
url: `/pages/order/create?items=${encodeURIComponent(JSON.stringify(orderData))}`
});
}
},
// 返回首页
goHome() {
uni.switchTab({
url: '/pages/index/index'
});
},
// 跳转到购物车
async goToCart() {
const token = await uni.getStorageSync('access_token')
if (!token) {
uni.navigateTo({
url: '/pages/login/index'
})
return
}
uni.navigateTo({
url: '/pages/shoppingCart/index'
});
},
async fetchCartSelectedCount() {
const token = await uni.getStorageSync('access_token')
if (!token) {
return
}
try {
const res = await request('xcx/carts', 'GET', { page: 1, page_size: 99 });
const list = res.list || res.data || res || [];
this.cartSelectedCount = list
.filter(item => item && item.selected === 1)
.reduce((sum, item) => {
const quantity = parseInt(item.quantity || item.count || 0, 10);
return sum + (isNaN(quantity) ? 0 : quantity);
}, 0);
} catch (error) {
console.error('获取购物车数量失败:', error);
}
},
async fetchProductReviews(reset = false) {
if (!this.productInfo || this.isLoadingReviews) {
return;
}
if (!this.productInfo.product_id && !this.productInfo.id) {
console.warn('缺少商品ID无法获取评价');
return;
}
if (reset) {
this.reviewPage = 1;
this.reviews = [];
this.reviewsTotal = 0;
}
this.isLoadingReviews = true;
try {
const response = await request('xcx/order/reviews', 'GET', {
product_id: this.productInfo.product_id || this.productInfo.id,
page: this.reviewPage,
page_size: this.reviewPageSize
});
const list = response?.list || [];
const total = typeof response?.total === 'number' ? response.total : this.reviewsTotal;
this.reviews = reset ? list : [...this.reviews, ...list];
this.reviewsTotal = total || this.reviews.length;
console.log(this.reviews)
if (list.length > 0) {
this.reviewPage += 1;
}
} catch (error) {
console.error('获取商品评价失败:', error);
uni.showToast({
title: '获取评价失败',
icon: 'none'
});
} finally {
this.isLoadingReviews = false;
}
},
async loadMoreReviews() {
if (!this.hasMoreReviews || this.isLoadingReviews) {
return;
}
await this.fetchProductReviews();
}
}
};
</script>
<style scoped>
.detail-page {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 120rpx;
}
/* 图片轮播 */
.image-swiper-wrapper {
position: relative;
width: 100%;
height: 750rpx;
background-color: #fff;
}
.image-swiper {
width: 100%;
height: 100%;
}
/* 自定义指示器样式 */
.image-swiper ::v-deep .uni-swiper-dot {
width: 12rpx;
height: 12rpx;
border-radius: 6rpx;
background-color: rgba(0, 0, 0, 0.2);
}
.image-swiper ::v-deep .uni-swiper-dot-active {
width: 24rpx;
background-color: #fff;
}
.swiper-image {
width: 100%;
height: 100%;
}
.swiper-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 60rpx;
height: 60rpx;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
}
.swiper-nav.prev {
left: 24rpx;
}
.swiper-nav.next {
right: 24rpx;
}
.swiper-nav text {
font-size: 48rpx;
color: #666;
font-weight: bold;
line-height: 1;
}
/* 右上角分享按钮 */
.share-btn-top {
position: absolute;
top: 24rpx;
right: 24rpx;
z-index: 20;
width: 80rpx;
height: 80rpx;
background-color: rgba(0, 0, 0, 0.3);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.share-btn-inner-top {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: transparent;
border: 0!important;
padding: 0;
box-shadow: none!important;
}
.share-btn-inner-top .iconfont {
font-size: 40rpx;
color: #fff;
}
/* 商品信息 */
.product-info {
background-color: #fff;
padding: 32rpx 24rpx;
margin-bottom: 20rpx;
}
.product-tags {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
margin-bottom: 24rpx;
}
.tag {
padding: 6rpx 16rpx;
border: 2rpx solid rgba(152, 16, 250, 0.6);
border-radius: 6rpx;
font-size: 22rpx;
color: rgba(152, 16, 250, 0.9);
background-color: transparent;
}
.product-name-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
}
.product-name {
font-size: 36rpx;
font-weight: bold;
color: #333;
line-height: 1.4;
flex: 1;
}
.like-btn-top {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
margin-left: 20rpx;
}
.like-btn-top .iconfont {
font-size: 44rpx;
}
.like-btn-top .heart-filled {
color: #e7000b;
}
.like-btn-top .heart-outline {
color: #ccc;
}
.product-sub-title {
font-size: 28rpx;
color: #999;
margin-bottom: 20rpx;
line-height: 1.4;
}
.product-rating {
display: flex;
align-items: center;
margin-bottom: 20rpx;
font-size: 26rpx;
}
.star-icon {
color: #ffd700;
font-size: 28rpx;
margin-right: 8rpx;
}
.rating-value {
color: #333;
font-weight: 500;
margin-right: 8rpx;
}
.rating-text {
color: #999;
margin-right: 24rpx;
}
.like-text {
color: #999;
}
.product-price {
display: flex;
align-items: baseline;
margin-bottom: 24rpx;
}
.current-price {
font-size: 48rpx;
font-weight: bold;
color: #e7000b;
margin-right: 16rpx;
}
.original-price {
font-size: 28rpx;
color: #999;
text-decoration: line-through;
}
.product-description {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
/* 购买选项弹窗 */
.purchase-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;
justify-content: center;
z-index: 1000;
animation: fadeIn 0.3s;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.modal-content {
width: 100%;
max-height: 80vh;
background-color: #fff;
border-radius: 32rpx 32rpx 0 0;
display: flex;
flex-direction: column;
animation: slideUp 0.3s;
}
@keyframes slideUp {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx 24rpx;
border-bottom: 2rpx solid #f5f5f5;
}
.modal-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.modal-close {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 48rpx;
color: #999;
}
.modal-body {
flex: 1;
padding: 32rpx 24rpx;
overflow-y: auto;
max-height: calc(80vh - 200rpx);
}
.modal-footer {
padding: 24rpx;
border-top: 2rpx solid #f5f5f5;
}
.modal-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
text-align: center;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 500;
}
.confirm-btn {
background: linear-gradient(135deg, #9810fa 0%, #7a0bc7 100%);
color: #fff;
}
/* SKU选择 */
.sku-selection {
margin-bottom: 32rpx;
}
.sku-title-row {
margin-bottom: 24rpx;
}
.sku-section-title {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.sku-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.sku-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx;
border: 2rpx solid #e5e5e5;
border-radius: 12rpx;
background-color: #fff;
transition: all 0.3s;
}
.sku-item.active {
border-color: #9810fa;
background-color: rgba(152, 16, 250, 0.05);
}
.sku-item.disabled {
opacity: 0.5;
background-color: #f5f5f5;
}
.sku-info {
flex: 1;
}
.sku-name {
font-size: 28rpx;
color: #333;
font-weight: 500;
margin-bottom: 12rpx;
}
.sku-price-row {
display: flex;
align-items: baseline;
gap: 16rpx;
margin-bottom: 8rpx;
}
.sku-price-text {
font-size: 32rpx;
color: #e7000b;
font-weight: bold;
}
.sku-original-price {
font-size: 24rpx;
color: #999;
text-decoration: line-through;
}
.sku-stock {
font-size: 24rpx;
color: #999;
}
.sku-check {
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #9810fa 0%, #7a0bc7 100%);
border-radius: 50%;
}
.sku-check .iconfont {
color: #fff;
font-size: 24rpx;
}
.sku-hint {
font-size: 24rpx;
color: #ff9800;
margin-top: 8rpx;
}
.quantity-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.quantity-label {
font-size: 28rpx;
color: #333;
}
.quantity-control {
display: flex;
align-items: center;
border: 2rpx solid #e5e5e5;
border-radius: 8rpx;
overflow: hidden;
}
.quantity-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 36rpx;
color: #666;
background-color: #f8f8f8;
}
.quantity-btn:active {
background-color: #e8e8e8;
}
.quantity-value {
min-width: 80rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: #333;
background-color: #fff;
border-left: 2rpx solid #e5e5e5;
border-right: 2rpx solid #e5e5e5;
}
.stock-info {
font-size: 24rpx;
color: #999;
margin-bottom: 16rpx;
}
.subtotal {
text-align: right;
font-size: 32rpx;
color: #e7000b;
font-weight: bold;
}
/* 导航标签 */
.nav-tabs {
display: flex;
background-color: #fff;
margin-bottom: 20rpx;
padding: 0 24rpx;
}
.nav-tab {
flex: 1;
text-align: center;
padding: 24rpx 0;
font-size: 28rpx;
color: #666;
position: relative;
}
.nav-tab.active {
color: #9810fa;
font-weight: 500;
}
.nav-tab.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background-color: #9810fa;
border-radius: 2rpx;
}
/* 内容区域 */
.content-section {
background-color: #fff;
padding: 32rpx 24rpx;
min-height: 400rpx;
}
.tab-content {
width: 100%;
}
.detail-section {
margin-bottom: 40rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 24rpx;
}
.fragrance-notes {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.note-item {
font-size: 28rpx;
line-height: 1.6;
}
.note-label {
color: #666;
font-weight: 500;
}
.note-content {
color: #333;
}
.ingredients {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
/* 服务保障 */
.service-guarantee {
margin-top: 20rpx;
margin-bottom: 40rpx;
/* border-top: 2rpx solid #f5f5f5; */
padding: 32rpx 24rpx;
background-color: #fff;
}
.guarantee-list {
display: flex;
justify-content: space-around;
align-items: center;
padding: 20rpx 0;
}
.guarantee-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.guarantee-icon {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
}
.guarantee-icon-1 {
background-color: rgba(76, 175, 80, 0.1);
color: #4caf50;
}
.guarantee-icon-2 {
background-color: rgba(33, 150, 243, 0.1);
color: #2196f3;
}
.guarantee-icon-3 {
background-color: rgba(156, 39, 176, 0.1);
color: #9c27b0;
}
.guarantee-icon .iconfont {
font-size: 48rpx;
}
.guarantee-icon text {
font-size: 48rpx;
line-height: 1;
}
.guarantee-text {
font-size: 24rpx;
color: #666;
}
.spec-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.spec-item {
font-size: 28rpx;
line-height: 1.6;
}
.spec-label {
color: #666;
font-weight: 500;
}
.spec-value {
color: #333;
}
.review-list {
display: flex;
flex-direction: column;
gap: 32rpx;
}
.review-item {
padding-bottom: 32rpx;
border-bottom: 2rpx solid #f5f5f5;
}
.review-item:last-child {
border-bottom: none;
}
.review-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.review-user {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.review-rating {
display: flex;
gap: 4rpx;
}
.review-rating .iconfont {
font-size: 24rpx;
color: #ffd700;
}
.review-user-info {
display: flex;
align-items: center;
max-width: 70%;
}
.review-avatar {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
margin-right: 16rpx;
background-color: #f5f5f5;
}
.review-user-text {
display: flex;
flex-direction: column;
}
.review-sku {
margin-top: 4rpx;
font-size: 24rpx;
color: #999;
}
.review-content {
font-size: 28rpx;
color: #666;
line-height: 1.6;
margin-bottom: 12rpx;
}
.review-time {
font-size: 24rpx;
color: #999;
}
.review-empty,
.review-loading {
text-align: center;
color: #999;
font-size: 26rpx;
padding: 40rpx 0;
}
.load-more-reviews {
margin-top: 24rpx;
text-align: center;
color: #9810fa;
font-size: 28rpx;
}
/* 底部操作栏 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 100rpx;
background-color: #fff;
display: flex;
align-items: center;
box-shadow: 0 -2rpx 8rpx rgba(0, 0, 0, 0.05);
z-index: 100;
}
.bar-btn {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #666;
padding: 12rpx 0;
box-sizing: border-box;
position: relative;
}
.bar-btn .iconfont {
font-size: 36rpx;
margin-bottom: 4rpx;
}
.bar-btn .heart-filled {
color: #e7000b;
}
.bar-btn .heart-outline {
color: #ccc;
}
.share-btn-inner {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: transparent;
border: 0;
padding: 0;
font-size: 24rpx;
color: #666;
}
.share-btn-inner .iconfont {
font-size: 36rpx;
margin-bottom: 4rpx;
}
.bar-btn.cart-btn {
flex: 2;
background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
color: #fff;
font-size: 28rpx;
font-weight: 500;
margin: 0 12rpx;
border-radius: 48rpx;
height: 72rpx;
line-height: 72rpx;
flex-direction: row;
}
.bar-btn.primary {
flex: 2;
background: linear-gradient(135deg, #9810fa 0%, #7a0bc7 100%);
color: #fff;
font-size: 32rpx;
font-weight: 500;
margin: 0 24rpx;
border-radius: 48rpx;
height: 72rpx;
line-height: 72rpx;
}
.cart-count {
position: absolute;
top: 6rpx;
right: 36rpx;
min-width: 32rpx;
padding: 0 8rpx;
height: 32rpx;
border-radius: 16rpx;
background-color: #ff4d4f;
color: #fff;
font-size: 20rpx;
line-height: 32rpx;
text-align: center;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.15);
}
</style>