2241 lines
59 KiB
Plaintext
2241 lines
59 KiB
Plaintext
<!-- 消费者端 - 商品详情页 -->
|
||
<template>
|
||
<view class="product-detail-page">
|
||
<scroll-view class="page-scroll" scroll-y="true">
|
||
<!-- 商品图片轮播 -->
|
||
<view class="product-images">
|
||
<swiper class="image-swiper" :indicator-dots="true" :autoplay="false" @change="onSwiperChange">
|
||
<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">
|
||
<!-- 会员折扣标签行 -->
|
||
<view v-if="memberDiscount > 0 && memberPrice > 0 && memberPrice < product.price" class="price-header">
|
||
<view class="member-badge">
|
||
<text class="member-badge-text">VIP</text>
|
||
</view>
|
||
<text class="member-discount-label">{{ memberDiscount }}折</text>
|
||
</view>
|
||
|
||
<!-- 价格行 -->
|
||
<view class="price-row">
|
||
<text class="price-symbol">¥</text>
|
||
<text class="price-value">{{ memberPrice > 0 && memberPrice < product.price ? memberPrice : product.price }}</text>
|
||
<text v-if="memberPrice > 0 && memberPrice < product.price" class="price-original">¥{{ product.price }}</text>
|
||
<text v-else-if="product.original_price != null && product.original_price > product.price" class="price-original">¥{{ product.original_price }}</text>
|
||
</view>
|
||
|
||
<!-- 节省金额 -->
|
||
<view v-if="memberPrice > 0 && memberPrice < product.price" class="save-row">
|
||
<text class="save-text">已省 ¥{{ (product.price - memberPrice).toFixed(2) }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="product-name-row">
|
||
<text class="product-name">{{ product.name }}</text>
|
||
<view class="share-btn" @click="showSharePopup">
|
||
<text class="share-icon">📤</text>
|
||
<text class="share-text">分享</text>
|
||
</view>
|
||
</view>
|
||
<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" @click.stop="goToShop">{{ merchant.shop_name }}</text>
|
||
<view class="shop-stats-row">
|
||
<text class="rating-text">评分: {{ merchant.rating.toFixed(1) }}</text>
|
||
<text class="sales-text">销量: {{ merchant.total_sales }}</text>
|
||
</view>
|
||
</view>
|
||
<text class="enter-shop" @click.stop="goToShop">进店 ❯</text>
|
||
</view>
|
||
|
||
<!-- 功能主治(药品功能) -->
|
||
<view class="function-section" v-if="product.usage">
|
||
<text class="function-title">功能主治</text>
|
||
<text class="function-content">{{ product.usage }}</text>
|
||
</view>
|
||
|
||
<!-- 优惠券入口 (新增) -->
|
||
<view class="detail-cell coupon-entry" @click="showCouponModal" v-if="coupons.length > 0">
|
||
<text class="cell-label">优惠</text>
|
||
<view class="cell-content flex-row">
|
||
<text class="coupon-tag" v-for="(coupon, index) in coupons.slice(0, 2)" :key="index">
|
||
{{ coupon.name }}
|
||
</text>
|
||
</view>
|
||
<text class="cell-arrow">领券 ❯</text>
|
||
</view>
|
||
|
||
<!-- 商品参数 -->
|
||
<view class="detail-cell params-section" @click="showParamsModal">
|
||
<text class="cell-label">参数</text>
|
||
<view class="cell-content">
|
||
<text class="params-summary-text">{{ getParamsSummary() }}</text>
|
||
</view>
|
||
<text class="cell-arrow">❯</text>
|
||
</view>
|
||
|
||
<!-- 规格选择 -->
|
||
<view class="detail-cell spec-section" @click="showSpecModal" v-if="productSkus.length > 0">
|
||
<text class="cell-label">规格</text>
|
||
<view class="cell-content">
|
||
<text class="spec-selected">{{ selectedSpec != '' ? selectedSpec : '请选择规格' }}</text>
|
||
</view>
|
||
<text class="cell-arrow">❯</text>
|
||
</view>
|
||
|
||
<!-- 数量选择 -->
|
||
<view class="detail-cell quantity-section">
|
||
<text class="cell-label">数量</text>
|
||
<view class="cell-content flex-row align-center justify-between">
|
||
<view class="quantity-selector flex-row align-center">
|
||
<view class="quantity-btn minus" @click="decreaseQuantity">
|
||
<text class="quantity-btn-text">-</text>
|
||
</view>
|
||
<input class="quantity-input"
|
||
type="number"
|
||
:value="quantity.toString()"
|
||
:min="1"
|
||
:max="getMaxQuantity()"
|
||
@input="validateQuantity" />
|
||
<view class="quantity-btn plus" @click="increaseQuantity">
|
||
<text class="quantity-btn-text">+</text>
|
||
</view>
|
||
</view>
|
||
<text class="quantity-stock">库存{{ getAvailableStock() }}件</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 商品详情 -->
|
||
<view class="product-description">
|
||
<view class="section-title">商品详情</view>
|
||
<text class="description-text">{{ product.description ?? '暂无详细描述' }}</text>
|
||
<!-- 商品详情图片 -->
|
||
<view class="detail-images" v-if="product.images.length > 0">
|
||
<image v-for="(img, index) in product.images"
|
||
:key="index"
|
||
:src="img"
|
||
class="detail-image"
|
||
mode="widthFix"
|
||
@click="previewImage(index)" />
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 底部操作栏 -->
|
||
<view class="bottom-actions">
|
||
<view class="action-buttons">
|
||
<!-- 客服按钮 -->
|
||
<view class="action-btn" @click="contactMerchant">
|
||
<image src="/static/icons/customer-service.png" class="action-icon-img" />
|
||
<text class="action-text">客服</text>
|
||
</view>
|
||
<view class="action-btn" @click="goToCart">
|
||
<image src="/static/tabbar/cart.png" class="action-icon-img" />
|
||
<text class="action-text">购物车</text>
|
||
</view>
|
||
<view class="action-btn" @click="toggleFavorite">
|
||
<image :src="isFavorite ? '/static/icons/favorite.png' : '/static/icons/favorite-active.png'" class="action-icon-img" />
|
||
<text class="action-text">{{ isFavorite ? '已收藏' : '收藏' }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="btn-group">
|
||
<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 v-if="selectedSkuId == ''" class="spec-error-tip">
|
||
<text class="error-tip-text">请选择规格</text>
|
||
</view>
|
||
<view class="spec-header-jd">
|
||
<image :src="getSelectedSkuImage()" class="spec-product-img" mode="aspectFill" />
|
||
<view class="spec-info-jd">
|
||
<view class="spec-price-row">
|
||
<text class="price-symbol">¥</text>
|
||
<text class="price-value">{{ getSelectedSkuPrice() }}</text>
|
||
</view>
|
||
<text class="spec-stock-jd">库存: {{ getSelectedSkuStock() }}件</text>
|
||
<text class="spec-choosed-jd">已选: {{ selectedSpec != '' ? selectedSpec : '请选择规格' }}</text>
|
||
</view>
|
||
<text class="close-btn-jd" @click="hideSpecModal">×</text>
|
||
</view>
|
||
|
||
<scroll-view class="spec-list-jd" scroll-y="true">
|
||
<view class="spec-group">
|
||
<text class="group-title">规格</text>
|
||
<view class="group-tags">
|
||
<view v-for="sku in productSkus" :key="sku.id"
|
||
class="spec-tag"
|
||
:class="{ active: selectedSkuId === sku.id }"
|
||
@click="selectSku(sku)">
|
||
<text class="tag-text">{{ getSkuSpecText(sku) }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 数量选择移入弹窗内容 -->
|
||
<view class="spec-quantity-row">
|
||
<text class="group-title">数量</text>
|
||
<view class="quantity-selector-jd">
|
||
<view class="q-btn" @click="decreaseQuantity">
|
||
<text class="q-btn-text">-</text>
|
||
</view>
|
||
<input class="q-input" type="number" :value="quantity.toString()" @input="validateQuantity" />
|
||
<view class="q-btn" @click="increaseQuantity">
|
||
<text class="q-btn-text">+</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<view class="spec-footer-jd">
|
||
<button class="footer-btn cart" @click="addToCart">加入购物车</button>
|
||
<button class="footer-btn buy" @click="buyNow">立即购买</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 商品参数弹窗 -->
|
||
<view v-if="showParams" class="params-modal" @click="hideParamsModal">
|
||
<view class="params-content" @click.stop>
|
||
<view class="params-header">
|
||
<text class="params-title">商品参数</text>
|
||
<text class="close-btn" @click="hideParamsModal">×</text>
|
||
</view>
|
||
<scroll-view class="params-list" direction="vertical">
|
||
<view class="params-item" v-if="product.specification">
|
||
<text class="params-label">规格</text>
|
||
<text class="params-value">{{ product.specification }}</text>
|
||
</view>
|
||
<view class="params-item" v-if="product.usage">
|
||
<text class="params-label">功能主治</text>
|
||
<text class="params-value">{{ product.usage }}</text>
|
||
</view>
|
||
<view class="params-item" v-if="product.side_effects">
|
||
<text class="params-label">副作用</text>
|
||
<text class="params-value">{{ product.side_effects }}</text>
|
||
</view>
|
||
<view class="params-item" v-if="product.precautions">
|
||
<text class="params-label">注意事项</text>
|
||
<text class="params-value">{{ product.precautions }}</text>
|
||
</view>
|
||
<view class="params-item" v-if="product.expiry_date">
|
||
<text class="params-label">有效期</text>
|
||
<text class="params-value">{{ product.expiry_date }}</text>
|
||
</view>
|
||
<view class="params-item" v-if="product.storage_conditions">
|
||
<text class="params-label">储存条件</text>
|
||
<text class="params-value">{{ product.storage_conditions }}</text>
|
||
</view>
|
||
<view class="params-item" v-if="product.approval_number">
|
||
<text class="params-label">批准文号</text>
|
||
<text class="params-value">{{ product.approval_number }}</text>
|
||
</view>
|
||
<view class="params-item" v-if="product.tags != null && product.tags.length > 0">
|
||
<text class="params-label">标签</text>
|
||
<text class="params-value">{{ product.tags!.join(', ') }}</text>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 优惠券弹窗 (新增) -->
|
||
<view v-if="showCoupons" class="popup-mask" @click="hideCouponModal">
|
||
<view class="popup-content" @click.stop>
|
||
<view class="popup-header">
|
||
<text class="popup-title">优惠券</text>
|
||
<text class="close-btn" @click="hideCouponModal">×</text>
|
||
</view>
|
||
<scroll-view scroll-y="true" class="coupon-list-scroll">
|
||
<view v-for="coupon in coupons" :key="coupon.id" class="coupon-item">
|
||
<view class="coupon-left">
|
||
<text class="coupon-amount">
|
||
<text class="symbol">¥</text>{{ coupon.discount_value }}
|
||
</text>
|
||
<text class="coupon-cond">满{{ coupon.min_order_amount }}可用</text>
|
||
</view>
|
||
<view class="coupon-right">
|
||
<view class="coupon-info-text">
|
||
<text class="coupon-name">{{ coupon.name }}</text>
|
||
<text class="coupon-time">{{ formatDate(coupon.start_time) }}-{{ formatDate(coupon.end_time) }}</text>
|
||
</view>
|
||
<button class="coupon-btn" @click="claimCoupon(coupon)">领取</button>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 分享弹窗 -->
|
||
<view v-if="showShare" class="share-popup-mask" @click="hideSharePopup">
|
||
<view class="share-popup-content" @click.stop>
|
||
<view class="share-popup-header">
|
||
<text class="share-popup-title">分享至</text>
|
||
<text class="close-btn" @click="hideSharePopup">×</text>
|
||
</view>
|
||
|
||
<!-- 分享选项 -->
|
||
<view class="share-options">
|
||
<view class="share-option" @click="shareToWechat">
|
||
<view class="share-icon-wrapper wechat">
|
||
<text class="share-option-icon">💬</text>
|
||
</view>
|
||
<text class="share-option-text">微信好友</text>
|
||
</view>
|
||
<view class="share-option" @click="shareToMoments">
|
||
<view class="share-icon-wrapper moments">
|
||
<text class="share-option-icon">🔄</text>
|
||
</view>
|
||
<text class="share-option-text">朋友圈</text>
|
||
</view>
|
||
<view class="share-option" @click="shareToQQ">
|
||
<view class="share-icon-wrapper qq">
|
||
<text class="share-option-icon">🐧</text>
|
||
</view>
|
||
<text class="share-option-text">QQ</text>
|
||
</view>
|
||
<view class="share-option" @click="copyLink">
|
||
<view class="share-icon-wrapper link">
|
||
<text class="share-option-icon">🔗</text>
|
||
</view>
|
||
<text class="share-option-text">复制链接</text>
|
||
</view>
|
||
<view class="share-option" @click="saveImage">
|
||
<view class="share-icon-wrapper image">
|
||
<text class="share-option-icon">🖼️</text>
|
||
</view>
|
||
<text class="share-option-text">保存图片</text>
|
||
</view>
|
||
<view class="share-option" @click="generatePoster">
|
||
<view class="share-icon-wrapper poster">
|
||
<text class="share-option-icon">📋</text>
|
||
</view>
|
||
<text class="share-option-text">生成海报</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 取消按钮 -->
|
||
<view class="share-cancel-btn" @click="hideSharePopup">
|
||
<text class="cancel-text">取消</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { ProductType, MerchantType, ProductSkuType, CouponTemplateType, FootprintItemType } from '@/types/mall-types.uts'
|
||
import { supabaseService } from '@/utils/supabaseService.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 as number,
|
||
isFavorite: false,
|
||
showParams: false,
|
||
// 新增: 优惠券相关
|
||
coupons: [] as Array<CouponTemplateType>,
|
||
showCoupons: false,
|
||
// 分享相关
|
||
showShare: false,
|
||
// 会员价相关
|
||
memberPrice: 0 as number,
|
||
memberDiscount: 0 as number,
|
||
memberLevelName: '' as string
|
||
}
|
||
},
|
||
onLoad(options: any) {
|
||
const opts = options as UTSJSONObject
|
||
const productId = (opts['productId'] ?? opts['id']) as string | null
|
||
const priceStr = opts['price'] as string | null
|
||
const productPrice = priceStr != null ? parseFloat(priceStr) : null
|
||
const originalPriceStr = opts['originalPrice'] as string | null
|
||
const productOriginalPrice = originalPriceStr != null ? parseFloat(originalPriceStr) : null
|
||
|
||
let productName = opts['name'] as string | null
|
||
if (productName != null) {
|
||
try {
|
||
const decodedName = decodeURIComponent(productName)
|
||
productName = decodedName
|
||
} catch (e) {
|
||
console.warn('ProductName decode failed, using original:', productName)
|
||
}
|
||
}
|
||
|
||
let productImage = opts['image'] as string | null
|
||
if (productImage != null) {
|
||
try {
|
||
const decodedImage = decodeURIComponent(productImage)
|
||
productImage = decodedImage
|
||
} catch (e) {
|
||
console.warn('ProductImage decode failed, using original:', productImage)
|
||
}
|
||
}
|
||
|
||
if (productId != null) {
|
||
this.loadProductDetail(productId, {
|
||
price: productPrice,
|
||
originalPrice: productOriginalPrice,
|
||
name: productName,
|
||
image: productImage
|
||
})
|
||
this.checkFavoriteStatus(productId)
|
||
this.saveFootprint(productId)
|
||
|
||
if (productName != null) {
|
||
uni.setNavigationBarTitle({
|
||
title: productName
|
||
})
|
||
}
|
||
}
|
||
},
|
||
computed: {
|
||
displayPrice(): number {
|
||
if (this.selectedSkuId != null && this.selectedSkuId !== '') {
|
||
const sku = this.productSkus.find(s => s.id === this.selectedSkuId)
|
||
if (sku != null) return sku!.price
|
||
}
|
||
return this.product.price
|
||
}
|
||
},
|
||
methods: {
|
||
saveFootprint(productId: string) {
|
||
// 调用后端API记录足迹
|
||
supabaseService.addFootprint(productId).then(success => {
|
||
if (success === true) {
|
||
console.log('足迹已同步到服务器')
|
||
}
|
||
})
|
||
|
||
const footprintData = uni.getStorageSync('footprints') as string | null
|
||
let footprints: Array<FootprintItemType> = []
|
||
|
||
if (footprintData != null && footprintData !== '') {
|
||
try {
|
||
footprints = JSON.parse(footprintData) as Array<FootprintItemType>
|
||
} catch (e) {
|
||
console.error('Failed to parse footprints', e)
|
||
}
|
||
}
|
||
|
||
// 移除已存在的相同商品(为了将其移到最新位置)
|
||
const productIdStr = productId
|
||
footprints = footprints.filter(function(item: any): boolean {
|
||
const itemObj = item as UTSJSONObject
|
||
const itemId = itemObj.getString('id') ?? ''
|
||
return itemId != productIdStr
|
||
})
|
||
|
||
// 添加到头部
|
||
const productImage = this.product.images.length > 0 ? this.product.images[0] : '/static/default-product.png'
|
||
footprints.unshift({
|
||
id: this.product.id,
|
||
name: this.product.name,
|
||
price: this.product.price,
|
||
original_price: this.product.original_price,
|
||
image: productImage,
|
||
sales: this.product.sales,
|
||
shopId: this.merchant.id,
|
||
shopName: this.merchant.shop_name,
|
||
viewTime: Date.now()
|
||
})
|
||
|
||
// 限制数量,例如最近50条
|
||
if (footprints.length > 50) {
|
||
footprints = footprints.slice(0, 50)
|
||
}
|
||
uni.setStorageSync('footprints', JSON.stringify(footprints))
|
||
},
|
||
|
||
async loadProductDetail(productId: string, options: any = {}) {
|
||
uni.showLoading({ title: '加载中...' })
|
||
try {
|
||
const dbProduct = await supabaseService.getProductById(productId)
|
||
|
||
if (dbProduct != null) {
|
||
// 使用 getProductById 返回的 Product 对象
|
||
this.product = {
|
||
id: dbProduct.id,
|
||
merchant_id: dbProduct.merchant_id ?? '',
|
||
category_id: dbProduct.category_id ?? '',
|
||
name: dbProduct.name,
|
||
description: dbProduct.description ?? '',
|
||
images: dbProduct.images ?? [] as string[],
|
||
price: dbProduct.price ?? dbProduct.base_price ?? 0,
|
||
original_price: dbProduct.original_price ?? dbProduct.market_price ?? 0,
|
||
stock: dbProduct.stock ?? dbProduct.total_stock ?? 0,
|
||
sales: dbProduct.sale_count ?? 0,
|
||
status: dbProduct.status ?? 1,
|
||
created_at: dbProduct.created_at ?? new Date().toISOString(),
|
||
specification: dbProduct.specification ?? null,
|
||
usage: dbProduct.usage ?? null,
|
||
side_effects: dbProduct.side_effects ?? null,
|
||
precautions: dbProduct.precautions ?? null,
|
||
expiry_date: dbProduct.expiry_date ?? null,
|
||
storage_conditions: dbProduct.storage_conditions ?? null,
|
||
approval_number: dbProduct.approval_number ?? null,
|
||
tags: [] as string[]
|
||
} as ProductType
|
||
|
||
// 解析 tags
|
||
if (dbProduct.tags != null && dbProduct.tags != '') {
|
||
try {
|
||
const parsedTags = JSON.parse(dbProduct.tags)
|
||
if (Array.isArray(parsedTags)) {
|
||
this.product.tags = (parsedTags as any[]).map((t: any): string => t as string)
|
||
}
|
||
} catch(e) {}
|
||
}
|
||
|
||
// Handle Images - 使用 main_image_url 作为后备
|
||
if (this.product.images.length == 0 && dbProduct.main_image_url != null && dbProduct.main_image_url != '') {
|
||
this.product.images.push(dbProduct.main_image_url)
|
||
}
|
||
// Final fallback
|
||
if (this.product.images.length == 0) {
|
||
this.product.images.push('/static/default-product.png')
|
||
}
|
||
|
||
console.log('商品详情加载成功:', this.product.name, '库存:', this.product.stock, '销量:', this.product.sales)
|
||
} else {
|
||
throw new Error('No product found')
|
||
}
|
||
} catch (e) {
|
||
console.error('Failed to load product detail:', e)
|
||
// Fallback to options if available
|
||
this.product.id = productId
|
||
const opts = options as UTSJSONObject
|
||
const nameOpt = opts['name']
|
||
this.product.name = (nameOpt != null && nameOpt != '') ? decodeURIComponent(nameOpt as string) ?? '未知商品' : '未知商品'
|
||
|
||
// price 可能是 string 或 number 类型
|
||
const priceOpt = opts['price']
|
||
if (typeof priceOpt == 'number') {
|
||
this.product.price = priceOpt as number
|
||
} else if (typeof priceOpt == 'string') {
|
||
this.product.price = parseFloat(priceOpt as string)
|
||
} else {
|
||
this.product.price = 0
|
||
}
|
||
|
||
const imageOpt = opts['image']
|
||
const decodedImage = (imageOpt != null && imageOpt != '') ? decodeURIComponent(imageOpt as string) : null
|
||
this.product.images = decodedImage != null ? [decodedImage] : ['/static/default-product.png']
|
||
}
|
||
|
||
// Load Merchant and SKUs
|
||
if (this.product.merchant_id != null && this.product.merchant_id !== '') {
|
||
await this.loadMerchantInfo(this.product.merchant_id)
|
||
// 加载优惠券
|
||
this.loadCoupons()
|
||
}
|
||
if (this.product.id != null && this.product.id !== '') {
|
||
this.loadProductSkus(this.product.id)
|
||
}
|
||
|
||
// 加载会员价
|
||
this.loadMemberPrice()
|
||
|
||
uni.hideLoading()
|
||
},
|
||
|
||
async loadMerchantInfo(merchantId: string) {
|
||
let realMerchantLoaded = false
|
||
if (merchantId.includes('-') || !merchantId.startsWith('merchant_')) {
|
||
try {
|
||
const shopResponse = await supabaseService.getShopByMerchantId(merchantId)
|
||
if (shopResponse != null) {
|
||
// 直接使用 Shop 对象的属性
|
||
this.merchant = {
|
||
id: shopResponse.id,
|
||
user_id: shopResponse.merchant_id,
|
||
shop_name: shopResponse.shop_name,
|
||
shop_logo: shopResponse.shop_logo ?? '/static/default-shop.png',
|
||
shop_banner: shopResponse.shop_banner ?? '/static/default-banner.png',
|
||
shop_description: shopResponse.description ?? '',
|
||
contact_name: shopResponse.contact_name ?? '店主',
|
||
contact_phone: shopResponse.contact_phone ?? '',
|
||
shop_status: 1,
|
||
rating: shopResponse.rating_avg ?? 5.0,
|
||
total_sales: shopResponse.total_sales ?? 0,
|
||
created_at: shopResponse.created_at ?? new Date().toISOString()
|
||
} as MerchantType
|
||
realMerchantLoaded = true
|
||
console.log('店铺信息加载成功:', this.merchant.shop_name)
|
||
}
|
||
} catch (e) {
|
||
console.error('Load shop failed', e)
|
||
}
|
||
}
|
||
|
||
if (!realMerchantLoaded) {
|
||
let charSum: number = 0
|
||
for (let i = 0; i < merchantId.length; i++) {
|
||
const charCode = merchantId.charCodeAt(i)
|
||
if (charCode != null) {
|
||
charSum += charCode
|
||
}
|
||
}
|
||
const merchantIndex = Math.abs(charSum) % 5
|
||
const shopNames = ['优质好店', '品牌直营店', '官方旗舰店', '专卖店', '精品小店']
|
||
|
||
this.merchant = {
|
||
id: merchantId,
|
||
user_id: 'user_mock_' + merchantIndex,
|
||
shop_name: shopNames[merchantIndex],
|
||
shop_logo: '/static/shop-logo.png',
|
||
shop_banner: '/static/shop-banner.png',
|
||
shop_description: '优质服务,正品保障',
|
||
contact_name: '店主',
|
||
contact_phone: '',
|
||
shop_status: 1,
|
||
rating: 4.8,
|
||
total_sales: 999,
|
||
created_at: '2023-01-01'
|
||
} as MerchantType
|
||
}
|
||
},
|
||
|
||
async loadProductSkus(productId: string) {
|
||
// 尝试从数据库加载SKU
|
||
try {
|
||
const skus = await supabaseService.getProductSkus(productId)
|
||
if (skus.length > 0) {
|
||
console.log('加载到商品SKU:', skus.length)
|
||
this.productSkus = []
|
||
for (let i = 0; i < skus.length; i++) {
|
||
const skuData = skus[i]
|
||
// 解析 specifications JSON 字符串
|
||
let specs: UTSJSONObject = {}
|
||
if (skuData.specifications != null && skuData.specifications != '') {
|
||
try {
|
||
specs = JSON.parse(skuData.specifications) as UTSJSONObject
|
||
} catch(e) {
|
||
console.error('解析SKU规格失败', e)
|
||
}
|
||
}
|
||
const sku: ProductSkuType = {
|
||
id: skuData.id,
|
||
product_id: skuData.product_id,
|
||
sku_code: skuData.sku_code,
|
||
specifications: specs,
|
||
price: skuData.price,
|
||
stock: skuData.stock ?? 0,
|
||
image_url: skuData.image_url ?? '',
|
||
status: skuData.status ?? 1
|
||
}
|
||
this.productSkus.push(sku)
|
||
}
|
||
return
|
||
}
|
||
} catch (e) {
|
||
console.error('Fetch SKUs error', e)
|
||
}
|
||
},
|
||
|
||
async loadMemberPrice() {
|
||
try {
|
||
const memberInfo = await supabaseService.getUserMemberInfo()
|
||
const levelNameRaw = memberInfo.get('level_name')
|
||
const discountRaw = memberInfo.get('discount')
|
||
|
||
if (levelNameRaw != null) {
|
||
this.memberLevelName = levelNameRaw as string
|
||
}
|
||
|
||
if (discountRaw != null) {
|
||
const discountRate = discountRaw as number
|
||
// discountRate 是折扣率,如 0.9 表示 9 折
|
||
// 会员价 = 原价 × 折扣率
|
||
if (discountRate > 0 && discountRate < 1) {
|
||
// 计算折扣显示值:0.9 -> 9 折
|
||
this.memberDiscount = Math.round(discountRate * 10) / 10 * 10
|
||
// 计算会员价:原价 × 折扣率
|
||
this.memberPrice = Math.round(this.product.price * discountRate * 100) / 100
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.log('获取会员信息失败,可能未登录或非会员:', e)
|
||
}
|
||
},
|
||
|
||
// 新增:加载优惠券
|
||
async loadCoupons() {
|
||
if (this.product.merchant_id == '') return
|
||
// Safety check for cached service definition
|
||
try {
|
||
const couponData = await supabaseService.fetchShopCoupons(this.product.merchant_id)
|
||
// 解析优惠券数据
|
||
this.coupons = []
|
||
if (couponData != null && couponData.length > 0) {
|
||
for (let i = 0; i < couponData.length; i++) {
|
||
const item = couponData[i]
|
||
const couponObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
|
||
|
||
const getSafeString = (key: string): string => {
|
||
const val = couponObj.get(key)
|
||
if (val == null) return ''
|
||
if (typeof val == 'string') return val
|
||
return ''
|
||
}
|
||
|
||
const getSafeNumber = (key: string): number => {
|
||
const val = couponObj.get(key)
|
||
if (val == null) return 0
|
||
if (typeof val == 'number') return val
|
||
return 0
|
||
}
|
||
|
||
const coupon: CouponTemplateType = {
|
||
id: getSafeString('id'),
|
||
name: getSafeString('name'),
|
||
description: getSafeString('description'),
|
||
coupon_type: getSafeNumber('coupon_type'),
|
||
discount_type: getSafeNumber('discount_type'),
|
||
discount_value: getSafeNumber('discount_value'),
|
||
min_order_amount: getSafeNumber('min_order_amount'),
|
||
max_discount_amount: getSafeNumber('max_discount_amount'),
|
||
total_quantity: getSafeNumber('total_quantity'),
|
||
per_user_limit: getSafeNumber('per_user_limit'),
|
||
usage_limit: getSafeNumber('usage_limit'),
|
||
merchant_id: getSafeString('merchant_id'),
|
||
category_ids: [] as string[],
|
||
product_ids: [] as string[],
|
||
user_type_limit: getSafeNumber('user_type_limit'),
|
||
start_time: getSafeString('start_time'),
|
||
end_time: getSafeString('end_time'),
|
||
status: getSafeNumber('status'),
|
||
created_at: getSafeString('created_at')
|
||
}
|
||
this.coupons.push(coupon)
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.warn('SupabaseService coupon methods not available:', e)
|
||
}
|
||
},
|
||
|
||
// 新增:联系客服(商家)
|
||
contactMerchant() {
|
||
if (supabaseService.getCurrentUserId() == '') {
|
||
uni.navigateTo({ url: '/pages/auth/login' })
|
||
return
|
||
}
|
||
// Navigate to chat
|
||
const merchId = this.merchant.user_id ?? this.merchant.id ?? this.product.merchant_id;
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/chat?merchantId=${merchId}&merchantName=${this.merchant.shop_name}`
|
||
})
|
||
},
|
||
|
||
// 新增:优惠券弹窗
|
||
showCouponModal() {
|
||
this.showCoupons = true
|
||
},
|
||
hideCouponModal() {
|
||
this.showCoupons = false
|
||
},
|
||
|
||
// 新增:领取优惠券
|
||
async claimCoupon(coupon: CouponTemplateType) {
|
||
const userId = supabaseService.getCurrentUserId()
|
||
if (userId == '') {
|
||
uni.navigateTo({ url: '/pages/auth/login' })
|
||
return
|
||
}
|
||
uni.showLoading({ title: '领取中' })
|
||
|
||
let success = false
|
||
const couponId = coupon.id
|
||
try {
|
||
// @ts-ignore
|
||
success = await supabaseService.claimShopCoupon(couponId, userId!)
|
||
} catch (e) {
|
||
try {
|
||
// @ts-ignore
|
||
success = await supabaseService.claimCoupon(couponId, userId!)
|
||
} catch (e2) {
|
||
console.warn('claimCoupon method missing:', e2)
|
||
}
|
||
}
|
||
|
||
},
|
||
|
||
getSelectedSkuImage(): string {
|
||
if (this.selectedSkuId != '') {
|
||
const sku = this.productSkus.find(s => s.id === this.selectedSkuId)
|
||
if (sku != null && sku.image_url != null && sku.image_url != '') {
|
||
return sku.image_url as string
|
||
}
|
||
}
|
||
return this.product.images.length > 0 ? this.product.images[0] : '/static/default-product.png'
|
||
},
|
||
|
||
getSelectedSkuPrice(): string {
|
||
if (this.selectedSkuId != '') {
|
||
const sku = this.productSkus.find(s => s.id === this.selectedSkuId)
|
||
if (sku != null) return sku.price.toFixed(2)
|
||
}
|
||
return this.product.price.toFixed(2)
|
||
},
|
||
|
||
getSelectedSkuStock(): number {
|
||
if (this.selectedSkuId != '') {
|
||
const sku = this.productSkus.find(s => s.id === this.selectedSkuId)
|
||
this.showSpecModal()
|
||
if (sku != null) return sku.stock
|
||
}
|
||
return this.product.stock
|
||
if (success === true) {
|
||
uni.showToast({ title: '领取成功', icon: 'success' })
|
||
} else {
|
||
uni.showToast({ title: '领取失败或已领取', icon: 'none' })
|
||
}
|
||
},
|
||
|
||
formatDate(dateStr: string): string {
|
||
if (dateStr == '') return ''
|
||
const date = new Date(dateStr)
|
||
return `${date.getFullYear()}.${date.getMonth()+1}.${date.getDate()}`
|
||
},
|
||
|
||
onSwiperChange(e: any) {
|
||
const eventObj = e as UTSJSONObject
|
||
const detail = eventObj['detail'] as UTSJSONObject
|
||
this.currentImageIndex = detail['current'] as number
|
||
},
|
||
|
||
showSpecModal() {
|
||
this.showSpec = true
|
||
},
|
||
|
||
hideSpecModal() {
|
||
this.showSpec = false
|
||
},
|
||
|
||
selectSku(sku: ProductSkuType) {
|
||
this.selectedSkuId = sku.id
|
||
this.selectedSpec = this.getSkuSpecText(sku)
|
||
},
|
||
|
||
getSkuSpecText(sku: ProductSkuType): string {
|
||
if (sku.specifications != null) {
|
||
const specs = sku.specifications as UTSJSONObject
|
||
let specStr = ''
|
||
// 在 UTS 中遍历 UTSJSONObject 的推荐方式
|
||
for (const key in specs) {
|
||
const val = specs[key]
|
||
if (val != null) {
|
||
specStr += (specStr === '' ? '' : ' ') + val.toString()
|
||
}
|
||
}
|
||
if (specStr !== '') {
|
||
return specStr
|
||
}
|
||
}
|
||
return sku.sku_code ?? ''
|
||
},
|
||
|
||
async addToCart() {
|
||
if (this.productSkus.length > 0 && (this.selectedSkuId == null || this.selectedSkuId === '')) {
|
||
if (!this.showSpec) {
|
||
this.showSpecModal()
|
||
}
|
||
return
|
||
}
|
||
|
||
uni.showLoading({ title: '添加中...' })
|
||
|
||
try {
|
||
const success = await supabaseService.addToCart(
|
||
this.product.id,
|
||
this.quantity,
|
||
this.selectedSkuId,
|
||
this.product.merchant_id
|
||
)
|
||
uni.hideLoading()
|
||
|
||
if (success === true) {
|
||
uni.showToast({ title: '已添加到购物车', icon: 'success' })
|
||
this.hideSpecModal()
|
||
} else {
|
||
console.error('添加购物车返回失败')
|
||
uni.showToast({ title: '添加失败,请登录重试', icon: 'none' })
|
||
}
|
||
} catch (e) {
|
||
uni.hideLoading()
|
||
console.error('添加购物车异常', e)
|
||
uni.showToast({ title: '添加异常', icon: 'none' })
|
||
}
|
||
},
|
||
|
||
buyNow() {
|
||
if (this.productSkus.length > 0 && (this.selectedSkuId == null || this.selectedSkuId === '')) {
|
||
if (!this.showSpec) {
|
||
this.showSpecModal()
|
||
}
|
||
return
|
||
}
|
||
|
||
const sku = (this.selectedSkuId != null && this.selectedSkuId !== '') ? this.productSkus.find(s => s.id === this.selectedSkuId) : null
|
||
|
||
const selectedItem = {
|
||
id: this.selectedSkuId,
|
||
product_id: this.product.id,
|
||
sku_id: this.selectedSkuId,
|
||
product_name: this.product.name,
|
||
product_image: (sku != null && sku.image_url != null) ? sku!.image_url : this.product.images[0],
|
||
sku_specifications: sku != null ? sku!.specifications : {},
|
||
price: parseFloat((sku != null ? sku!.price : this.product.price).toString()).toFixed(2) as string,
|
||
quantity: this.quantity as number,
|
||
shop_id: this.merchant.id,
|
||
shop_name: this.merchant.shop_name,
|
||
merchant_id: this.merchant.user_id ?? this.product.merchant_id
|
||
}
|
||
|
||
uni.setStorageSync('checkout_type', 'buy_now')
|
||
uni.setStorageSync('checkout_items', JSON.stringify([selectedItem]))
|
||
|
||
uni.navigateTo({
|
||
url: '/pages/mall/consumer/checkout'
|
||
})
|
||
},
|
||
|
||
checkFavoriteStatus(id: string) {
|
||
this.checkFavorite(id)
|
||
},
|
||
|
||
async checkFavorite(id: string) {
|
||
const isFav = await supabaseService.checkFavorite(id)
|
||
this.isFavorite = isFav
|
||
},
|
||
|
||
async toggleFavorite() {
|
||
if (this.product.id == '') return
|
||
uni.showLoading({ title: '处理中' })
|
||
|
||
try {
|
||
const wasFavorite = this.isFavorite
|
||
const isNowFavorite = await supabaseService.toggleFavorite(this.product.id)
|
||
uni.hideLoading()
|
||
|
||
if (isNowFavorite !== wasFavorite) {
|
||
this.isFavorite = isNowFavorite
|
||
uni.showToast({
|
||
title: isNowFavorite ? '收藏成功' : '已取消收藏',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({ title: '操作失败', icon: 'none' })
|
||
this.checkFavoriteStatus(this.product.id)
|
||
}
|
||
} catch (e) {
|
||
uni.hideLoading()
|
||
console.error('Toggle favorite failed', e)
|
||
uni.showToast({ title: '操作异常', icon: 'none' })
|
||
}
|
||
},
|
||
|
||
goToHome() {
|
||
uni.switchTab({ url: '/pages/mall/consumer/home' })
|
||
},
|
||
|
||
goToShop() {
|
||
const merchantId = this.merchant.id ?? this.product.merchant_id ?? ''
|
||
if (merchantId != '') {
|
||
console.log('进店点击,merchantId:', merchantId)
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/shop-detail?merchantId=${merchantId}`
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: '店铺信息加载中',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
goToCart() {
|
||
uni.switchTab({ url: '/pages/main/cart' })
|
||
},
|
||
|
||
decreaseQuantity() {
|
||
if (this.quantity > 1) {
|
||
this.quantity--
|
||
}
|
||
},
|
||
|
||
increaseQuantity() {
|
||
const maxQuantity = this.getMaxQuantity()
|
||
if (this.quantity < maxQuantity) {
|
||
this.quantity++
|
||
} else {
|
||
uni.showToast({ title: `最多只能购买${maxQuantity}件`, icon: 'none' })
|
||
}
|
||
},
|
||
|
||
validateQuantity() {
|
||
let num = this.quantity
|
||
const maxQuantity = this.getMaxQuantity()
|
||
if (num < 1) num = 1
|
||
else if (num > maxQuantity) {
|
||
num = maxQuantity
|
||
uni.showToast({ title: `最多只能购买${maxQuantity}件`, icon: 'none' })
|
||
}
|
||
this.quantity = num
|
||
},
|
||
|
||
getMaxQuantity() {
|
||
if (this.selectedSkuId != null && this.selectedSkuId !== '') {
|
||
const sku = this.productSkus.find(s => s.id === this.selectedSkuId)
|
||
if (sku != null) return sku!.stock
|
||
}
|
||
return this.product.stock
|
||
},
|
||
|
||
getAvailableStock() {
|
||
return this.getMaxQuantity()
|
||
},
|
||
|
||
previewImage(index: number) {
|
||
uni.previewImage({
|
||
current: index,
|
||
urls: this.product.images
|
||
})
|
||
},
|
||
|
||
showParamsModal() {
|
||
this.showParams = true
|
||
},
|
||
|
||
hideParamsModal() {
|
||
this.showParams = false
|
||
},
|
||
|
||
getParamsSummary(): string {
|
||
let summary = ''
|
||
if (this.product.specification != null && (this.product.specification as string) != '') summary += '规格 '
|
||
if (this.product.expiry_date != null && (this.product.expiry_date as string) != '') summary += '有效期 '
|
||
if (this.product.approval_number != null && (this.product.approval_number as string) != '') summary += '批准文号 '
|
||
const finalSummary = summary.trim()
|
||
return finalSummary != '' ? finalSummary : '查看详情'
|
||
},
|
||
|
||
// 分享相关方法
|
||
showSharePopup() {
|
||
this.showShare = true
|
||
},
|
||
|
||
hideSharePopup() {
|
||
this.showShare = false
|
||
},
|
||
|
||
shareToWechat() {
|
||
this.hideSharePopup()
|
||
// #ifdef MP-WEIXIN
|
||
// 小程序分享
|
||
uni.share({
|
||
provider: 'weixin',
|
||
scene: 'WXSceneSession',
|
||
type: 0,
|
||
title: this.product.name,
|
||
summary: `¥${this.product.price} - ${this.product.description ?? '精选好物'}`,
|
||
imageUrl: this.product.images.length > 0 ? this.product.images[0] : '',
|
||
success: () => {
|
||
uni.showToast({ title: '分享成功', icon: 'success' })
|
||
},
|
||
fail: (err) => {
|
||
console.error('分享失败', err)
|
||
uni.showToast({ title: '分享失败', icon: 'none' })
|
||
}
|
||
})
|
||
// #endif
|
||
// #ifndef MP-WEIXIN
|
||
uni.showToast({ title: '请在微信中打开分享', icon: 'none' })
|
||
// #endif
|
||
},
|
||
|
||
shareToMoments() {
|
||
this.hideSharePopup()
|
||
// #ifdef MP-WEIXIN
|
||
uni.share({
|
||
provider: 'weixin',
|
||
scene: 'WXSceneTimeline',
|
||
type: 0,
|
||
title: this.product.name,
|
||
summary: `¥${this.product.price} - ${this.product.description ?? '精选好物'}`,
|
||
imageUrl: this.product.images.length > 0 ? this.product.images[0] : '',
|
||
success: () => {
|
||
uni.showToast({ title: '分享成功', icon: 'success' })
|
||
},
|
||
fail: (err) => {
|
||
console.error('分享失败', err)
|
||
uni.showToast({ title: '分享失败', icon: 'none' })
|
||
}
|
||
})
|
||
// #endif
|
||
// #ifndef MP-WEIXIN
|
||
uni.showToast({ title: '请在微信中打开分享', icon: 'none' })
|
||
// #endif
|
||
},
|
||
|
||
shareToQQ() {
|
||
this.hideSharePopup()
|
||
uni.showToast({ title: 'QQ分享开发中', icon: 'none' })
|
||
},
|
||
|
||
copyLink() {
|
||
this.hideSharePopup()
|
||
const shareLink = `pages/mall/consumer/product-detail?id=${this.product.id}`
|
||
uni.setClipboardData({
|
||
data: shareLink,
|
||
success: () => {
|
||
uni.showToast({ title: '链接已复制', icon: 'success' })
|
||
}
|
||
})
|
||
},
|
||
|
||
saveImage() {
|
||
this.hideSharePopup()
|
||
if (this.product.images.length > 0) {
|
||
uni.showLoading({ title: '保存中...' })
|
||
uni.downloadFile({
|
||
url: this.product.images[0],
|
||
success: (res) => {
|
||
uni.saveImageToPhotosAlbum({
|
||
filePath: res.tempFilePath,
|
||
success: () => {
|
||
uni.hideLoading()
|
||
uni.showToast({ title: '已保存到相册', icon: 'success' })
|
||
},
|
||
fail: () => {
|
||
uni.hideLoading()
|
||
uni.showToast({ title: '保存失败', icon: 'none' })
|
||
}
|
||
})
|
||
},
|
||
fail: () => {
|
||
uni.hideLoading()
|
||
uni.showToast({ title: '下载失败', icon: 'none' })
|
||
}
|
||
})
|
||
} else {
|
||
uni.showToast({ title: '暂无图片可保存', icon: 'none' })
|
||
}
|
||
},
|
||
|
||
generatePoster() {
|
||
this.hideSharePopup()
|
||
uni.showToast({ title: '海报生成功能开发中', icon: 'none' })
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.product-detail-page {
|
||
background-color: #f5f5f5;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.page-scroll {
|
||
flex: 1;
|
||
height: 0;
|
||
width: 100%;
|
||
}
|
||
|
||
.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;
|
||
background: linear-gradient(135deg, #fff5f0 0%, #ffffff 100%);
|
||
border-radius: 16rpx;
|
||
padding: 20rpx;
|
||
margin: -10rpx -10rpx 20rpx -10rpx;
|
||
}
|
||
|
||
.price-header {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.member-badge {
|
||
background: linear-gradient(135deg, #ff5000 0%, #ff7a00 100%);
|
||
border-radius: 6rpx;
|
||
padding: 4rpx 16rpx;
|
||
margin-right: 12rpx;
|
||
}
|
||
|
||
.member-badge-text {
|
||
font-size: 22rpx;
|
||
color: #fff;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.member-discount-label {
|
||
font-size: 26rpx;
|
||
color: #ff5000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.price-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.price-symbol {
|
||
font-size: 32rpx;
|
||
color: #ff5000;
|
||
font-weight: bold;
|
||
margin-right: 4rpx;
|
||
}
|
||
|
||
.price-value {
|
||
font-size: 56rpx;
|
||
color: #ff5000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.price-original {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
text-decoration-line: line-through;
|
||
margin-left: 16rpx;
|
||
}
|
||
|
||
.save-row {
|
||
margin-top: 12rpx;
|
||
}
|
||
|
||
.save-text {
|
||
font-size: 24rpx;
|
||
color: #52c41a;
|
||
background-color: #f6ffed;
|
||
padding: 6rpx 16rpx;
|
||
border-radius: 6rpx;
|
||
}
|
||
|
||
.current-price {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #ff5000;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.member-price-tag {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #52c41a;
|
||
background-color: #f6ffed;
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 8rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.member-discount-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
margin-bottom: 15rpx;
|
||
margin-top: 10rpx;
|
||
}
|
||
|
||
.member-tag {
|
||
font-size: 20rpx;
|
||
color: #fff;
|
||
background: linear-gradient(135deg, #ff5000 0%, #ff7a00 100%);
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 4rpx;
|
||
margin-right: 10rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.member-discount-text {
|
||
font-size: 24rpx;
|
||
color: #ff5000;
|
||
font-weight: bold;
|
||
margin-right: 15rpx;
|
||
}
|
||
|
||
.member-save-text {
|
||
font-size: 22rpx;
|
||
color: #52c41a;
|
||
}
|
||
|
||
.current-price.has-discount {
|
||
color: #ff5000;
|
||
}
|
||
|
||
.original-price {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
text-decoration-line: line-through;
|
||
}
|
||
|
||
.product-name {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
line-height: 1.4;
|
||
flex: 1;
|
||
}
|
||
|
||
.product-name-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.share-btn {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 8rpx 16rpx;
|
||
background-color: #f8f8f8;
|
||
border-radius: 12rpx;
|
||
flex-shrink: 0;
|
||
margin-left: 20rpx;
|
||
}
|
||
|
||
.share-icon {
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.share-text {
|
||
font-size: 22rpx;
|
||
color: #666;
|
||
margin-top: 4rpx;
|
||
}
|
||
|
||
.sales-info {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.shop-info {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
.shop-logo {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 10rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.shop-details {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
|
||
.shop-name {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.shop-stats-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
.rating-text, .sales-text {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-right: 30rpx;
|
||
}
|
||
|
||
.enter-shop {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
}
|
||
|
||
/* Modal Popup Styles */
|
||
.popup-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
flex-direction: column;
|
||
z-index: 1000;
|
||
}
|
||
.popup-content {
|
||
background-color: #fff;
|
||
width: 100%;
|
||
border-radius: 20rpx 20rpx 0 0;
|
||
padding: 30rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
max-height: 1000rpx;
|
||
}
|
||
.popup-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30rpx;
|
||
padding-bottom: 20rpx;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
.popup-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
.close-btn {
|
||
font-size: 48rpx;
|
||
color: #999;
|
||
}
|
||
.coupon-list-scroll {
|
||
flex: 1;
|
||
}
|
||
.coupon-item {
|
||
display: flex;
|
||
background-color: #fff5f5;
|
||
border-radius: 10rpx;
|
||
padding: 20rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
.coupon-left {
|
||
width: 180rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
border-right: 1px dashed #ffccc7;
|
||
color: #ff5000;
|
||
}
|
||
.coupon-amount {
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
}
|
||
.symbol {
|
||
font-size: 24rpx;
|
||
}
|
||
.coupon-cond {
|
||
font-size: 22rpx;
|
||
margin-top: 5rpx;
|
||
}
|
||
.coupon-right {
|
||
flex: 1;
|
||
padding-left: 20rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.coupon-info-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.coupon-name {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
.coupon-time {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
}
|
||
.coupon-btn {
|
||
background-color: #ff5000;
|
||
color: #fff;
|
||
font-size: 24rpx;
|
||
padding: 0 24rpx;
|
||
height: 50rpx;
|
||
line-height: 50rpx;
|
||
border-radius: 25rpx;
|
||
margin: 0;
|
||
}
|
||
|
||
.product-description {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
padding-bottom: 140rpx;
|
||
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;
|
||
}
|
||
|
||
/* 统一Cell样式优化 */
|
||
.detail-cell {
|
||
background-color: #fff;
|
||
padding: 32rpx 30rpx;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
border-bottom: 1rpx solid #f8f8f8;
|
||
}
|
||
|
||
.cell-label {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
width: 90rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.cell-content {
|
||
flex: 1;
|
||
margin-left: 10rpx;
|
||
}
|
||
|
||
.cell-arrow {
|
||
font-size: 24rpx;
|
||
color: #ccc;
|
||
margin-left: 10rpx;
|
||
}
|
||
|
||
/* 覆盖具体板块样式 */
|
||
.coupon-entry, .params-section, .spec-section {
|
||
margin-bottom: 0; /* 连在一起显示 */
|
||
}
|
||
|
||
.quantity-section {
|
||
margin-bottom: 20rpx; /* 数量选择作为最后一项保留底边距 */
|
||
border-bottom: none;
|
||
}
|
||
|
||
.params-summary-text, .spec-selected {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.flex-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
}
|
||
|
||
.align-center {
|
||
align-items: center;
|
||
}
|
||
|
||
.justify-between {
|
||
justify-content: space-between;
|
||
}
|
||
|
||
/* 数量加减器样式 */
|
||
.quantity-selector {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
border: 1rpx solid #e5e5e5;
|
||
border-radius: 8rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.quantity-btn {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.quantity-btn.minus {
|
||
border-right: 1rpx solid #e5e5e5;
|
||
}
|
||
|
||
.quantity-btn.plus {
|
||
border-left: 1rpx solid #e5e5e5;
|
||
}
|
||
|
||
.quantity-btn-text {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.quantity-input {
|
||
width: 80rpx;
|
||
height: 60rpx;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
border: none;
|
||
background-color: #fff;
|
||
}
|
||
|
||
.quantity-stock {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.bottom-actions {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: #fff;
|
||
padding: 10rpx 20rpx;
|
||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.action-buttons {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.action-btn {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 20rpx;
|
||
min-width: 80rpx;
|
||
}
|
||
|
||
.action-icon-img {
|
||
width: 44rpx;
|
||
height: 44rpx;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
|
||
.action-text {
|
||
font-size: 20rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.btn-group {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
.cart-btn, .buy-btn {
|
||
flex: 1;
|
||
height: 72rpx;
|
||
line-height: 72rpx;
|
||
border-radius: 36rpx;
|
||
font-size: 26rpx;
|
||
border: none;
|
||
margin: 0 10rpx;
|
||
}
|
||
|
||
.cart-btn {
|
||
background-color: #ff5000;
|
||
opacity: 0.8;
|
||
color: #fff;
|
||
}
|
||
|
||
.buy-btn {
|
||
background-color: #ff5000;
|
||
color: #fff;
|
||
}
|
||
|
||
.spec-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.6);
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
flex-direction: column;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.spec-content {
|
||
background-color: #fff;
|
||
width: 100%;
|
||
border-radius: 24rpx 24rpx 0 0;
|
||
padding: 30rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
max-height: 80vh;
|
||
position: relative; /* 确保子元素绝对定位相对于此容器 */
|
||
}
|
||
|
||
.spec-header-jd {
|
||
display: flex;
|
||
flex-direction: row;
|
||
position: relative;
|
||
padding-bottom: 30rpx;
|
||
border-bottom: 1rpx solid #f2f2f2;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.spec-product-img {
|
||
width: 180rpx;
|
||
height: 180rpx;
|
||
border-radius: 12rpx;
|
||
margin-top: -60rpx;
|
||
background-color: #fff;
|
||
border: 4rpx solid #fff;
|
||
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.spec-info-jd {
|
||
flex: 1;
|
||
margin-left: 24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
padding-bottom: 10rpx;
|
||
}
|
||
|
||
.spec-price-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: baseline;
|
||
color: #fa2c19;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.price-symbol {
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.price-value {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 规格未选提示样式 */
|
||
.spec-error-tip {
|
||
position: absolute;
|
||
top: -80rpx;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background-color: rgba(0, 0, 0, 0.7);
|
||
padding: 12rpx 30rpx;
|
||
border-radius: 40rpx;
|
||
z-index: 2000;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.error-tip-text {
|
||
color: #fff;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.spec-stock-jd {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.spec-choosed-jd {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.close-btn-jd {
|
||
font-size: 48rpx;
|
||
color: #999;
|
||
position: absolute;
|
||
right: -10rpx;
|
||
top: -10rpx;
|
||
padding: 10rpx;
|
||
}
|
||
|
||
.spec-list-jd {
|
||
flex: 1;
|
||
overflow-y: hidden;
|
||
}
|
||
|
||
.spec-group {
|
||
padding: 30rpx 0;
|
||
}
|
||
|
||
.group-title {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 24rpx;
|
||
display: block;
|
||
}
|
||
|
||
.group-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.spec-tag {
|
||
background-color: #f6f6f6;
|
||
padding: 16rpx 32rpx;
|
||
border-radius: 40rpx;
|
||
margin-right: 20rpx;
|
||
margin-bottom: 20rpx;
|
||
border: 2rpx solid #f6f6f6;
|
||
}
|
||
|
||
.spec-tag.active {
|
||
background-color: #fcedeb;
|
||
border-color: #fa2c19;
|
||
}
|
||
|
||
.spec-tag.active .tag-text {
|
||
color: #fa2c19;
|
||
}
|
||
|
||
.tag-text {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.spec-quantity-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 30rpx 0;
|
||
}
|
||
|
||
.quantity-selector-jd {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
background-color: #f6f6f6;
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
.q-btn {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.q-btn-text {
|
||
font-size: 36rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.q-input {
|
||
width: 80rpx;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.spec-footer-jd {
|
||
display: flex;
|
||
flex-direction: row;
|
||
padding: 20rpx 0 10rpx;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.footer-btn {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
border-radius: 40rpx;
|
||
margin: 0 10rpx;
|
||
border: none;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.footer-btn.cart {
|
||
background: linear-gradient(90deg, #ffba0d, #ffc30d);
|
||
color: #fff;
|
||
}
|
||
|
||
.footer-btn.buy {
|
||
background: linear-gradient(90deg, #f2140c, #f2270c);
|
||
color: #fff;
|
||
}
|
||
|
||
/* 功能主治样式 */
|
||
.function-section {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.function-title {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.function-content {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* 商品参数样式 */
|
||
.params-section {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.params-title {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
width: 120rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.params-summary {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
}
|
||
|
||
.params-item {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
line-height: 1.5;
|
||
margin-right: 20rpx;
|
||
margin-bottom: 5rpx;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.params-arrow {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
flex-shrink: 0;
|
||
margin-left: 10rpx;
|
||
}
|
||
|
||
/* 分享弹窗样式 */
|
||
.share-popup-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
flex-direction: column;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.share-popup-content{
|
||
background-color: #fff;
|
||
width: 100%;
|
||
border-radius: 24rpx 24rpx 0 0;
|
||
padding: 30rpx;
|
||
padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
|
||
}
|
||
|
||
.share-popup-header{
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.share-popup-title{
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.share-options{
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-start;
|
||
padding: 20rpx 0;
|
||
}
|
||
|
||
.share-option{
|
||
width: 25%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.share-icon-wrapper{
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.share-icon-wrapper.wechat{
|
||
background-color: #07C160;
|
||
}
|
||
|
||
.share-icon-wrapper.moments{
|
||
background-color: #07C160;
|
||
}
|
||
|
||
.share-icon-wrapper.qq{
|
||
background-color: #12B7F5;
|
||
}
|
||
|
||
.share-icon-wrapper.link{
|
||
background-color: #FF9500;
|
||
}
|
||
|
||
.share-icon-wrapper.image{
|
||
background-color: #FF2D55;
|
||
}
|
||
|
||
.share-icon-wrapper.poster{
|
||
background-color: #5856D6;
|
||
}
|
||
|
||
.share-option-icon{
|
||
font-size: 44rpx;
|
||
color: #fff;
|
||
}
|
||
|
||
.share-option-text{
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.share-cancel-btn{
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background-color: #f5f5f5;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.cancel-text{
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
}
|
||
|
||
/* 商品参数弹窗样式 */
|
||
.params-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: flex-end; /* UVUE 推荐用 flex 布局对齐 */
|
||
flex-direction: column;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.params-content {
|
||
background-color: #fff;
|
||
width: 100%;
|
||
border-radius: 20rpx 20rpx 0 0;
|
||
padding: 30rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
max-height: 1000rpx;
|
||
}
|
||
|
||
.params-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30rpx;
|
||
padding-bottom: 20rpx;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.params-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
width: auto;
|
||
}
|
||
|
||
.params-list {
|
||
flex: 1;
|
||
}
|
||
|
||
.params-item {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
padding: 20rpx 0;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
}
|
||
|
||
.params-label {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
width: 150rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.params-value {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* 商品详情图片样式 */
|
||
.detail-images {
|
||
margin-top: 30rpx;
|
||
}
|
||
|
||
.detail-image {
|
||
width: 100%;
|
||
margin-bottom: 20rpx;
|
||
border-radius: 10rpx;
|
||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
/* 电脑端适配 */
|
||
@media (min-width: 768px) {
|
||
.params-section {
|
||
padding: 20rpx 30rpx;
|
||
}
|
||
|
||
.params-summary {
|
||
flex-wrap: nowrap;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.params-item {
|
||
flex: 1;
|
||
margin-right: 0;
|
||
text-align: center;
|
||
padding: 0 10rpx;
|
||
}
|
||
|
||
.params-arrow {
|
||
margin-left: 20rpx;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
|
||
|