2025-12-22 18:14:11 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="product-detail">
|
|
|
|
|
|
<!-- 加载状态 -->
|
|
|
|
|
|
<div v-if="productLoading" class="loading-container">
|
|
|
|
|
|
<el-skeleton :rows="10" animated />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 无商品数据提示 -->
|
|
|
|
|
|
<div v-else-if="!product.id" class="empty-container">
|
|
|
|
|
|
<el-empty description="商品不存在或链接已过期">
|
|
|
|
|
|
<p class="empty-tip">该商品链接可能已失效,请联系商家获取新的商品链接</p>
|
|
|
|
|
|
</el-empty>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 商品详情内容 -->
|
|
|
|
|
|
<template v-else>
|
|
|
|
|
|
<!-- 商品基本信息区域 -->
|
|
|
|
|
|
<div class="product-main">
|
|
|
|
|
|
<!-- 左侧商品图片 -->
|
|
|
|
|
|
<div class="product-images">
|
|
|
|
|
|
<div class="main-image">
|
|
|
|
|
|
<el-image
|
|
|
|
|
|
:src="currentImage"
|
|
|
|
|
|
:preview-src-list="product.mainImages || []"
|
|
|
|
|
|
fit="contain"
|
|
|
|
|
|
class="main-img"
|
|
|
|
|
|
:lazy="true"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #error>
|
|
|
|
|
|
<div class="image-slot">
|
|
|
|
|
|
<el-icon><Picture /></el-icon>
|
|
|
|
|
|
<div>图片加载失败</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-image>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="thumbnail-list" v-if="product.mainImages && product.mainImages.length > 1">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="(img, index) in product.mainImages"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
class="thumbnail-item"
|
|
|
|
|
|
:class="{ active: currentImageIndex === index }"
|
|
|
|
|
|
@click="selectImage(index)"
|
2025-12-23 17:49:51 +08:00
|
|
|
|
@mouseenter="hoverImage(img)"
|
|
|
|
|
|
@mouseleave="hoverImage(null)"
|
2025-12-22 18:14:11 +08:00
|
|
|
|
>
|
|
|
|
|
|
<el-image :src="img" fit="cover" class="thumbnail-img" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧商品信息 -->
|
|
|
|
|
|
<div class="product-info">
|
|
|
|
|
|
<h1 class="product-title">{{ product.name }}</h1>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 货币选择(如果有多个货币) -->
|
|
|
|
|
|
<div class="currency-selector" v-if="Object.keys(skusByCurrency).length > 1">
|
|
|
|
|
|
<span class="selector-label">选择货币:</span>
|
|
|
|
|
|
<el-radio-group v-model="currentCurrency" size="small">
|
|
|
|
|
|
<el-radio-button
|
|
|
|
|
|
v-for="(skus, currency) in skusByCurrency"
|
|
|
|
|
|
:key="currency"
|
|
|
|
|
|
:label="currency"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ getCurrencyName(currency) }}
|
|
|
|
|
|
</el-radio-button>
|
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- SKU选择区域 -->
|
|
|
|
|
|
<div class="sku-selection-section" v-if="currentCurrencySkus.length > 0">
|
|
|
|
|
|
<div class="sku-section-title">选择商品规格(SKU)</div>
|
|
|
|
|
|
<div class="sku-list">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="(sku, index) in currentCurrencySkus"
|
|
|
|
|
|
:key="sku.id || index"
|
|
|
|
|
|
:class="['sku-item', {
|
|
|
|
|
|
active: selectedSku && selectedSku.id === sku.id,
|
|
|
|
|
|
disabled: !sku.stock || sku.stock === 0
|
|
|
|
|
|
}]"
|
|
|
|
|
|
@click="selectSku(sku)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="sku-info">
|
|
|
|
|
|
<div class="sku-name">{{ sku.sku }}</div>
|
|
|
|
|
|
<div class="sku-price-stock">
|
|
|
|
|
|
<span class="sku-price">{{ sku.currency }} {{ formatPrice(sku.price) }}</span>
|
|
|
|
|
|
<span class="sku-stock" :class="{ 'stock-zero': !sku.stock || sku.stock === 0 }">
|
|
|
|
|
|
库存:{{ sku.stock || 0 }}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="sku-check" v-if="selectedSku && selectedSku.id === sku.id">
|
|
|
|
|
|
<el-icon><Check /></el-icon>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="sku-disabled-mask" v-if="!sku.stock || sku.stock === 0">
|
|
|
|
|
|
缺货
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-else class="no-sku-tip">
|
|
|
|
|
|
<el-alert type="warning" :closable="false">
|
|
|
|
|
|
暂无可用SKU
|
|
|
|
|
|
</el-alert>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 价格区域(显示选中SKU的价格) -->
|
|
|
|
|
|
<div class="price-section" v-if="selectedSku">
|
|
|
|
|
|
<div class="price-label">现价</div>
|
|
|
|
|
|
<div class="price-main">
|
|
|
|
|
|
<span class="currency">{{ selectedSku.currency }}</span>
|
|
|
|
|
|
<span class="price">{{ formatPrice(selectedSku.price) }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="price-section" v-else>
|
|
|
|
|
|
<div class="price-label">请选择SKU查看价格</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 数量选择 -->
|
|
|
|
|
|
<div class="quantity-section">
|
|
|
|
|
|
<div class="quantity-label">数量:</div>
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="quantity"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="selectedSku ? (selectedSku.stock || 999) : 999"
|
|
|
|
|
|
:disabled="!selectedSku || !selectedSku.stock || selectedSku.stock === 0"
|
|
|
|
|
|
class="quantity-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span class="stock-info">库存:{{ selectedSku ? (selectedSku.stock || 0) : '请选择SKU' }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 服务保障 -->
|
|
|
|
|
|
<div class="service-section">
|
|
|
|
|
|
<div class="service-item">
|
|
|
|
|
|
<el-icon><Goods /></el-icon>
|
|
|
|
|
|
<span>7天无理由退货</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="service-item">
|
|
|
|
|
|
<el-icon><Lock /></el-icon>
|
|
|
|
|
|
<span>正品保证</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="service-item">
|
|
|
|
|
|
<el-icon><Clock /></el-icon>
|
|
|
|
|
|
<span>极速发货</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 操作按钮 -->
|
|
|
|
|
|
<div class="action-buttons">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
class="buy-now-btn"
|
|
|
|
|
|
@click="handleBuyNow"
|
|
|
|
|
|
:loading="loading"
|
|
|
|
|
|
:disabled="!selectedSku || !selectedSku.stock || selectedSku.stock === 0"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-icon><ShoppingCart /></el-icon>
|
|
|
|
|
|
立即购买
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 商品详情区域 -->
|
|
|
|
|
|
<div class="product-tabs">
|
|
|
|
|
|
<el-tabs v-model="activeTab" class="detail-tabs">
|
|
|
|
|
|
<el-tab-pane label="商品详情" name="detail">
|
|
|
|
|
|
<div class="tab-content">
|
|
|
|
|
|
<div v-if="product.description" v-html="product.description" class="product-description"></div>
|
|
|
|
|
|
<div v-else class="empty-description">
|
|
|
|
|
|
<el-empty description="暂无商品详情" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
<el-tab-pane label="规格参数" name="params">
|
|
|
|
|
|
<div class="tab-content">
|
|
|
|
|
|
<el-descriptions :column="2" border v-if="selectedSku">
|
|
|
|
|
|
<el-descriptions-item label="SKU编码">{{ selectedSku.sku }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="价格">{{ selectedSku.currency }} {{ formatPrice(selectedSku.price) }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="库存">{{ selectedSku.stock || 0 }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="重量" v-if="selectedSku.weight">
|
|
|
|
|
|
{{ selectedSku.weight }}g
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="尺寸" v-if="selectedSku.size" :span="2">
|
|
|
|
|
|
{{ formatSize(selectedSku.size) }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
<el-empty v-else description="请先选择SKU查看规格参数" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
</el-tabs>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 购买确认对话框 -->
|
|
|
|
|
|
<el-dialog
|
|
|
|
|
|
v-model="showConfirmDialog"
|
|
|
|
|
|
title="确认购买信息"
|
|
|
|
|
|
width="600px"
|
|
|
|
|
|
:close-on-click-modal="false"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="confirm-dialog-content">
|
|
|
|
|
|
<!-- 商品信息 -->
|
|
|
|
|
|
<div class="confirm-product-info">
|
|
|
|
|
|
<el-image
|
|
|
|
|
|
:src="currentImage"
|
|
|
|
|
|
fit="cover"
|
|
|
|
|
|
class="confirm-product-image"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div class="confirm-product-details">
|
|
|
|
|
|
<div class="confirm-product-name">{{ product.name }}</div>
|
|
|
|
|
|
<div class="confirm-sku-info" v-if="selectedSku">
|
|
|
|
|
|
<span class="confirm-sku-label">SKU:</span>
|
|
|
|
|
|
<span class="confirm-sku-value">{{ selectedSku.sku }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 价格和数量 -->
|
|
|
|
|
|
<el-divider />
|
|
|
|
|
|
<div class="confirm-price-section">
|
|
|
|
|
|
<div class="confirm-price-item">
|
|
|
|
|
|
<span class="confirm-price-label">单价:</span>
|
|
|
|
|
|
<span class="confirm-price-value">
|
|
|
|
|
|
{{ selectedSku ? selectedSku.currency : '' }} {{ formatPrice(selectedSku ? selectedSku.price : 0) }}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="confirm-price-item">
|
|
|
|
|
|
<span class="confirm-price-label">数量:</span>
|
|
|
|
|
|
<span class="confirm-price-value">{{ quantity }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="confirm-price-item confirm-total">
|
|
|
|
|
|
<span class="confirm-price-label">总计:</span>
|
|
|
|
|
|
<span class="confirm-price-value confirm-total-price">
|
|
|
|
|
|
{{ selectedSku ? selectedSku.currency : '' }} {{ formatPrice(selectedSku ? (selectedSku.price * quantity) : 0) }}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div class="dialog-footer">
|
|
|
|
|
|
<el-button @click="showConfirmDialog = false">取消</el-button>
|
|
|
|
|
|
<el-button type="primary" @click="confirmBuy" :loading="loading">
|
|
|
|
|
|
确认购买
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, computed, onMounted, watch } from 'vue'
|
|
|
|
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
|
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
|
// 图标已全局注册在 main.js 中,直接使用组件名称即可
|
|
|
|
|
|
import { getProduct, getProductByLinkCode } from '../api/product'
|
|
|
|
|
|
import { formatAmount } from '../utils/helpers'
|
|
|
|
|
|
|
|
|
|
|
|
const route = useRoute()
|
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
|
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
const productLoading = ref(true)
|
|
|
|
|
|
const currentImageIndex = ref(0)
|
2025-12-23 17:49:51 +08:00
|
|
|
|
// 鼠标悬停的主图(优先展示)
|
|
|
|
|
|
const hoveredImage = ref(null)
|
2025-12-22 18:14:11 +08:00
|
|
|
|
const quantity = ref(1)
|
|
|
|
|
|
const activeTab = ref('detail')
|
|
|
|
|
|
const selectedSku = ref(null)
|
|
|
|
|
|
const showConfirmDialog = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
// 商品数据
|
|
|
|
|
|
const product = ref({
|
|
|
|
|
|
id: null,
|
|
|
|
|
|
name: '',
|
|
|
|
|
|
price: null,
|
|
|
|
|
|
mainImage: '',
|
|
|
|
|
|
mainImages: [],
|
|
|
|
|
|
status: '',
|
|
|
|
|
|
shopId: null,
|
|
|
|
|
|
skus: []
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 货币名称映射
|
|
|
|
|
|
const currencyNames = {
|
|
|
|
|
|
'USD': '美元',
|
|
|
|
|
|
'CNY': '人民币',
|
|
|
|
|
|
'MYR': '马来西亚林吉特',
|
|
|
|
|
|
'PHP': '菲律宾比索',
|
|
|
|
|
|
'THB': '泰铢',
|
|
|
|
|
|
'VND': '越南盾',
|
|
|
|
|
|
'SGD': '新加坡元',
|
|
|
|
|
|
'EUR': '欧元',
|
|
|
|
|
|
'GBP': '英镑'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 按货币分组SKU
|
|
|
|
|
|
const skusByCurrency = computed(() => {
|
|
|
|
|
|
if (!product.value.skus || product.value.skus.length === 0) {
|
|
|
|
|
|
return {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const grouped = {}
|
|
|
|
|
|
product.value.skus.forEach(sku => {
|
|
|
|
|
|
const currency = sku.currency || 'USD'
|
|
|
|
|
|
if (!grouped[currency]) {
|
|
|
|
|
|
grouped[currency] = []
|
|
|
|
|
|
}
|
|
|
|
|
|
grouped[currency].push(sku)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return grouped
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 当前货币(默认使用第一个货币)
|
|
|
|
|
|
const currentCurrency = ref('')
|
|
|
|
|
|
|
|
|
|
|
|
// 当前货币的SKU列表
|
|
|
|
|
|
const currentCurrencySkus = computed(() => {
|
|
|
|
|
|
if (!currentCurrency.value || !skusByCurrency.value[currentCurrency.value]) {
|
|
|
|
|
|
return []
|
|
|
|
|
|
}
|
|
|
|
|
|
return skusByCurrency.value[currentCurrency.value]
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 当前显示的图片
|
|
|
|
|
|
const currentImage = computed(() => {
|
2025-12-23 17:49:51 +08:00
|
|
|
|
// 1) 若有悬停主图,优先展示
|
|
|
|
|
|
if (hoveredImage.value) {
|
|
|
|
|
|
return hoveredImage.value
|
|
|
|
|
|
}
|
|
|
|
|
|
// 2) 已选SKU且有SKU图
|
2025-12-22 18:14:11 +08:00
|
|
|
|
if (selectedSku.value && selectedSku.value.skuImage) {
|
|
|
|
|
|
return selectedSku.value.skuImage
|
|
|
|
|
|
}
|
2025-12-23 17:49:51 +08:00
|
|
|
|
// 3) 主图列表
|
2025-12-22 18:14:11 +08:00
|
|
|
|
if (product.value.mainImages && product.value.mainImages.length > 0) {
|
|
|
|
|
|
return product.value.mainImages[currentImageIndex.value] || product.value.mainImages[0]
|
|
|
|
|
|
}
|
2025-12-23 17:49:51 +08:00
|
|
|
|
// 4) 兜底单张主图
|
2025-12-22 18:14:11 +08:00
|
|
|
|
return product.value.mainImage || ''
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 获取货币名称
|
|
|
|
|
|
const getCurrencyName = (currency) => {
|
|
|
|
|
|
return currencyNames[currency] || currency
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 选择SKU
|
|
|
|
|
|
const selectSku = (sku) => {
|
|
|
|
|
|
if (!sku.stock || sku.stock === 0) {
|
|
|
|
|
|
ElMessage.warning('该SKU已缺货')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
selectedSku.value = sku
|
|
|
|
|
|
// 如果SKU有图片,更新当前图片
|
|
|
|
|
|
if (sku.skuImage) {
|
|
|
|
|
|
const imageIndex = product.value.mainImages?.findIndex(img => img === sku.skuImage)
|
|
|
|
|
|
if (imageIndex >= 0) {
|
|
|
|
|
|
currentImageIndex.value = imageIndex
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化价格
|
|
|
|
|
|
const formatPrice = (price) => {
|
|
|
|
|
|
if (!price) return '0.00'
|
|
|
|
|
|
return formatAmount(price)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化尺寸
|
|
|
|
|
|
const formatSize = (sizeJson) => {
|
|
|
|
|
|
if (!sizeJson) return '-'
|
|
|
|
|
|
try {
|
|
|
|
|
|
const size = typeof sizeJson === 'string' ? JSON.parse(sizeJson) : sizeJson
|
|
|
|
|
|
if (size.length && size.width && size.height) {
|
|
|
|
|
|
return `${size.length} × ${size.width} × ${size.height} ${size.unit || 'cm'}`
|
|
|
|
|
|
}
|
|
|
|
|
|
return sizeJson
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
return sizeJson
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 选择图片
|
|
|
|
|
|
const selectImage = (index) => {
|
|
|
|
|
|
currentImageIndex.value = index
|
|
|
|
|
|
}
|
2025-12-23 17:49:51 +08:00
|
|
|
|
// 悬停主图时优先展示该主图
|
|
|
|
|
|
const hoverImage = (img) => {
|
|
|
|
|
|
hoveredImage.value = img
|
|
|
|
|
|
}
|
2025-12-22 18:14:11 +08:00
|
|
|
|
|
|
|
|
|
|
// 立即购买
|
|
|
|
|
|
const handleBuyNow = () => {
|
|
|
|
|
|
if (!selectedSku.value) {
|
|
|
|
|
|
ElMessage.warning('请先选择商品SKU')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (selectedSku.value.stock && quantity.value > selectedSku.value.stock) {
|
|
|
|
|
|
ElMessage.warning('库存不足')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
showConfirmDialog.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 确认购买
|
|
|
|
|
|
const confirmBuy = () => {
|
|
|
|
|
|
if (!selectedSku.value) {
|
|
|
|
|
|
ElMessage.warning('请先选择商品SKU')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
showConfirmDialog.value = false
|
|
|
|
|
|
|
|
|
|
|
|
// 构建订单数据
|
|
|
|
|
|
const orderData = {
|
|
|
|
|
|
product: {
|
|
|
|
|
|
id: product.value.id,
|
|
|
|
|
|
name: product.value.name,
|
|
|
|
|
|
price: selectedSku.value.price,
|
|
|
|
|
|
currency: selectedSku.value.currency,
|
|
|
|
|
|
sku: selectedSku.value.sku,
|
|
|
|
|
|
skuId: selectedSku.value.id,
|
|
|
|
|
|
quantity: quantity.value,
|
|
|
|
|
|
stock: selectedSku.value.stock || 0,
|
|
|
|
|
|
image: selectedSku.value.skuImage || currentImage.value
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到创建订单页面(填写收货信息)
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/create-order',
|
|
|
|
|
|
query: {
|
|
|
|
|
|
data: encodeURIComponent(JSON.stringify(orderData))
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 判断是否为链接码(32位字符串)
|
|
|
|
|
|
const isLinkCode = (id) => {
|
|
|
|
|
|
if (!id) return false
|
|
|
|
|
|
const idStr = String(id)
|
|
|
|
|
|
// 链接码是32位字符串(UUID去掉横线)
|
|
|
|
|
|
return idStr.length === 32 && /^[a-f0-9]+$/i.test(idStr)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加载商品详情
|
|
|
|
|
|
const loadProductDetail = async (id) => {
|
|
|
|
|
|
productLoading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
let response
|
|
|
|
|
|
// 判断是商品ID还是链接码
|
|
|
|
|
|
if (isLinkCode(id)) {
|
|
|
|
|
|
// 使用链接码获取商品
|
|
|
|
|
|
response = await getProductByLinkCode(id)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 使用商品ID获取商品
|
|
|
|
|
|
response = await getProduct(id)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (response.code === '0000' && response.data) {
|
|
|
|
|
|
product.value = response.data
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化货币选择(使用第一个货币)
|
|
|
|
|
|
const currencies = Object.keys(skusByCurrency.value)
|
|
|
|
|
|
if (currencies.length > 0) {
|
|
|
|
|
|
currentCurrency.value = currencies[0]
|
|
|
|
|
|
// 自动选择第一个有库存的SKU
|
|
|
|
|
|
const firstAvailableSku = currentCurrencySkus.value.find(sku => sku.stock && sku.stock > 0)
|
|
|
|
|
|
if (firstAvailableSku) {
|
|
|
|
|
|
selectedSku.value = firstAvailableSku
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(response.message || '获取商品详情失败')
|
|
|
|
|
|
// 如果获取失败,设置product.id为null以显示空状态
|
|
|
|
|
|
product.value.id = null
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载商品详情失败:', error)
|
|
|
|
|
|
ElMessage.error(error.response?.data?.message || '加载商品详情失败,请稍后重试')
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
productLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 监听货币变化,重置选中的SKU
|
|
|
|
|
|
watch(currentCurrency, () => {
|
|
|
|
|
|
selectedSku.value = null
|
|
|
|
|
|
const firstAvailableSku = currentCurrencySkus.value.find(sku => sku.stock && sku.stock > 0)
|
|
|
|
|
|
if (firstAvailableSku) {
|
|
|
|
|
|
selectedSku.value = firstAvailableSku
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
const id = route.params.id
|
|
|
|
|
|
if (id) {
|
|
|
|
|
|
loadProductDetail(id)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果没有ID,显示提示并停止加载
|
|
|
|
|
|
ElMessage.error('商品ID或链接码不能为空')
|
|
|
|
|
|
productLoading.value = false
|
|
|
|
|
|
// 客户访问时不应该跳转到管理页面,只显示错误提示
|
|
|
|
|
|
product.value.id = null
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.product-detail {
|
|
|
|
|
|
max-width: 1200px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
min-height: calc(100vh - 60px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.loading-container {
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
padding: 40px;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 商品主区域 */
|
|
|
|
|
|
.product-main {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 30px;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
padding: 40px;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 左侧图片区域 */
|
|
|
|
|
|
.product-images {
|
|
|
|
|
|
flex: 0 0 450px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.main-image {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 450px;
|
|
|
|
|
|
border: 1px solid #e8e8e8;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
background: #fafafa;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.main-image:hover {
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.main-img {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.image-slot {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumbnail-list {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumbnail-item {
|
|
|
|
|
|
width: 80px;
|
|
|
|
|
|
height: 80px;
|
|
|
|
|
|
border: 2px solid transparent;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumbnail-item:hover {
|
|
|
|
|
|
border-color: #409eff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumbnail-item.active {
|
|
|
|
|
|
border-color: #409eff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumbnail-img {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 右侧商品信息 */
|
|
|
|
|
|
.product-info {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
padding-left: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.product-title {
|
|
|
|
|
|
font-size: 26px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
margin: 0 0 20px 0;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
letter-spacing: 0.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 货币选择器 */
|
|
|
|
|
|
.currency-selector {
|
|
|
|
|
|
margin-bottom: 25px;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.selector-label {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
margin-right: 15px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* SKU选择区域 */
|
|
|
|
|
|
.sku-selection-section {
|
|
|
|
|
|
margin-bottom: 25px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-section-title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-list {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
max-height: 400px;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-item {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
border: 2px solid #e4e7ed;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-item:hover:not(.disabled) {
|
|
|
|
|
|
border-color: #409eff;
|
|
|
|
|
|
background: #f0f9ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-item.active:not(.disabled) {
|
|
|
|
|
|
border-color: #409eff;
|
|
|
|
|
|
background: #ecf5ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-item.disabled {
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
opacity: 0.6;
|
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-info {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-name {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-price-stock {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-price {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-stock {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-stock.stock-zero {
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-check {
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-disabled-mask {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 50%;
|
|
|
|
|
|
right: 50px;
|
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.6);
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
padding: 4px 12px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.no-sku-tip {
|
|
|
|
|
|
margin-bottom: 25px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 价格区域 */
|
|
|
|
|
|
.price-section {
|
|
|
|
|
|
background: linear-gradient(135deg, #fff5f5 0%, #ffeef0 100%);
|
|
|
|
|
|
padding: 25px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin-bottom: 25px;
|
|
|
|
|
|
border: 1px solid #ffe0e0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.price-label {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.price-main {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: baseline;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.currency {
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
margin-right: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.price {
|
|
|
|
|
|
font-size: 42px;
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
letter-spacing: -1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 数量选择 */
|
|
|
|
|
|
.quantity-section {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
margin-bottom: 25px;
|
|
|
|
|
|
padding: 15px 0;
|
|
|
|
|
|
border-top: 1px solid #eee;
|
|
|
|
|
|
border-bottom: 1px solid #eee;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.quantity-label {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.quantity-input {
|
|
|
|
|
|
width: 120px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stock-info {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 服务保障 */
|
|
|
|
|
|
.service-section {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 40px;
|
|
|
|
|
|
margin-bottom: 30px;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
background: linear-gradient(135deg, #f9f9f9 0%, #f5f5f5 100%);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid #eee;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.service-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.service-item .el-icon {
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 操作按钮 */
|
|
|
|
|
|
.action-buttons {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
margin-top: 30px;
|
|
|
|
|
|
padding-top: 20px;
|
|
|
|
|
|
border-top: 1px solid #eee;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.buy-now-btn {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 52px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
background: linear-gradient(135deg, #ff9500 0%, #ff6b00 100%);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(255, 107, 0, 0.3);
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.buy-now-btn:hover:not(:disabled) {
|
|
|
|
|
|
background: linear-gradient(135deg, #ff6b00 0%, #ff9500 100%);
|
|
|
|
|
|
box-shadow: 0 6px 16px rgba(255, 107, 0, 0.4);
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.pay-now-btn {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 52px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
background: linear-gradient(135deg, #f56c6c 0%, #ff4757 100%);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(245, 108, 108, 0.3);
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.pay-now-btn:hover:not(:disabled) {
|
|
|
|
|
|
background: linear-gradient(135deg, #ff4757 0%, #f56c6c 100%);
|
|
|
|
|
|
box-shadow: 0 6px 16px rgba(245, 108, 108, 0.4);
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 确认对话框样式 */
|
|
|
|
|
|
.confirm-dialog-content {
|
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-product-info {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 20px;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-product-image {
|
|
|
|
|
|
width: 120px;
|
|
|
|
|
|
height: 120px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid #e4e7ed;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-product-details {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-product-name {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-sku-info {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
border-left: 3px solid #409eff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-sku-label {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-sku-value {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
font-family: 'Courier New', monospace;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
padding: 2px 8px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
border: 1px solid #dcdfe6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-price-section {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-price-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 8px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-price-label {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-price-value {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-total {
|
|
|
|
|
|
padding-top: 12px;
|
|
|
|
|
|
border-top: 1px solid #e4e7ed;
|
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm-total-price {
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 商品详情标签页 */
|
|
|
|
|
|
.product-tabs {
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
padding: 30px;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-tabs {
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tab-content {
|
|
|
|
|
|
padding: 20px 0;
|
|
|
|
|
|
min-height: 300px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.product-description {
|
|
|
|
|
|
line-height: 1.8;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.empty-description {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
padding: 60px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 空状态容器 */
|
|
|
|
|
|
.empty-container {
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
padding: 60px 20px;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.empty-tip {
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 响应式设计 */
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
.product-detail {
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.product-main {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
gap: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.product-images {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.main-image {
|
|
|
|
|
|
height: 300px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.product-info {
|
|
|
|
|
|
padding-left: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.product-title {
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sku-list {
|
|
|
|
|
|
max-height: 300px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.action-buttons {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.buy-now-btn,
|
|
|
|
|
|
.pay-now-btn {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.service-section {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.currency-selector {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.selector-label {
|
|
|
|
|
|
margin-right: 0;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|