Files
vpUni/.svn/pristine/af/af6e6fc387be573530f5535d12f51d617358f9c3.svn-base
2026-03-09 16:39:03 +08:00

203 lines
6.6 KiB
Plaintext

<template>
<view class="product-detail-page">
<!-- 全新方案:纯 CSS 手动构建的骨架屏 -->
<view v-if="loading" class="skeleton-wrapper">
<view class="skeleton-item skeleton-rect" style="width: 100%; height: 750rpx;"></view>
<view class="skeleton-card" style="height: 200rpx;"></view>
<view class="skeleton-card" style="height: 100rpx;"></view>
<view class="skeleton-card">
<view class="skeleton-item skeleton-text" style="width: 200rpx; height: 32rpx; margin-bottom: 20rpx;"></view>
<view class="skeleton-item skeleton-rect" style="width: 100%; height: 300rpx;"></view>
</view>
</view>
<!-- 页面实际内容 -->
<view v-else class="page-content">
<scroll-view scroll-y>
<!-- 1. 商品轮播图 -->
<view class="swiper-section">
<swiper class="swiper-container" circular autoplay :interval="3000" :duration="500" @change="e => swiperCurrent = e.detail.current">
<swiper-item v-for="(item, index) in product.images" :key="index">
<view class="swiper-item">
<view class="image-placeholder swiper-image">
<image :src="item" style="width: 100%; height: 100%;" mode=""></image>
</view>
</view>
</swiper-item>
</swiper>
<view class="swiper-dots">{{ swiperCurrent + 1 }} / {{ product.images.length }}</view>
</view>
<!-- 2. 价格与商品信息 -->
<view class="card info-card">
<view class="price-line">
<text class="points">{{ product.points }} 积分</text>
<text class="original-price" v-if="product.originalPrice">+ ¥{{ product.originalPrice }}</text>
</view>
<text class="name">{{ product.name }}</text>
<view class="meta-line">
<text class="sales">已兑换 {{ product.sales }} 件</text>
<text class="stock">库存 {{ product.stock }} 件</text>
</view>
</view>
<!-- 3. 规格选择 -->
<view class="card spec-card">
<up-cell title="规格" value="默认" isLink></up-cell>
</view>
<!-- 4. 图文详情 -->
<view class="card detail-content-card">
<view class="section-title">
<text>图文详情</text>
</view>
<up-parse :content="product.detailHtml"></up-parse>
</view>
<!-- 5. 兑换须知 -->
<view class="card detail-content-card">
<view class="section-title">
<text>兑换须知</text>
</view>
<up-parse :content="product.noticeHtml"></up-parse>
</view>
</scroll-view>
<view class="" style=" height: 200rpx;">
</view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<button class="submit-btn">立即兑换</button>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { Service } from "@/Service/Service";
const loading = ref<boolean>(false);
const swiperCurrent = ref(0);
// 模拟的商品详情数据
const product = reactive({
images: [
'/static/dele/dele1.jpg',
'/static/dele/dele2.jpg',
],
name: '品牌充电宝 10000mAh 金属外壳 超薄便携 支持多种快充协议',
points: 2000,
originalPrice: 19.9,
sales: 128,
stock: 872,
detailHtml: `
<div style="padding: 10px 0;">
<p>这是一款设计精良的充电宝,小巧便携,功能强大。</p>
<p>采用高密度锂聚合物电芯,安全可靠。</p>
</div>
`,
noticeHtml: `
<div style="font-size: 14px; color: #666; line-height: 1.8;">
<p>1. 积分商品兑换后不支持退换。</p>
<p>2. 实物商品将在7个工作日内发货。</p>
<p>3. 虚拟卡券将以短信形式发送至您的手机。</p>
</div>
`,
});
onLoad((options) => {
// console.log('商品ID:', options?.id);
// 在这里根据 options.id 请求真实的商品详情数据
setTimeout(() => { loading.value = false; }, 1000);
});
onShow(() => {});
</script>
<style lang="scss" scoped>
@keyframes skeleton-blink { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
.skeleton-item { background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: skeleton-blink 1.5s infinite linear; }
.skeleton-rect { border-radius: 8rpx; }
.skeleton-text { border-radius: 4rpx; }
.skeleton-wrapper {
background-color: #f7f7f7;
.skeleton-card { background-color: #fff; padding: 30rpx; border-radius: 16rpx; margin: 24rpx; }
}
.product-detail-page {
background-color: #f7f7f7;
height: 100vh;
display: flex;
flex-direction: column;
}
.page-scroll {
flex: 1; height: 0; padding-bottom: 140rpx;
}
.card {
background-color: #fff; border-radius: 16rpx;
margin: 24rpx; padding: 30rpx;
box-shadow: 0 8rpx 30rpx rgba(220, 220, 230, 0.3);
}
.section-title {
font-size: 32rpx; font-weight: bold; color: #333; margin-bottom: 20rpx;
border-left: 8rpx solid #fa6400; padding-left: 16rpx;
}
.swiper-section {
position: relative;
.swiper-container { height: 750rpx; /* 1:1 的轮播图 */ }
.swiper-item { width: 100%; height: 100%; .swiper-image { width: 100%; height: 100%; } }
.swiper-dots {
position: absolute; bottom: 20rpx; right: 20rpx;
background-color: rgba(0,0,0,0.4); color: #fff;
padding: 4rpx 12rpx; border-radius: 20rpx; font-size: 24rpx;
}
}
.info-card {
margin-top: -20rpx; // 与轮播图重叠
position: relative;
.price-line {
display: flex; align-items: baseline;
.points { font-size: 48rpx; font-weight: bold; color: #fa6400; }
.original-price { font-size: 28rpx; color: #999; margin-left: 16rpx; }
}
.name {
font-size: 32rpx; font-weight: bold; color: #333;
margin: 16rpx 0; display: block;
}
.meta-line {
display: flex; justify-content: space-between;
font-size: 26rpx; color: #999;
}
}
.spec-card {
padding: 0;
:deep(.up-cell) { .up-cell__body { padding: 30rpx; } }
}
.detail-content-card {
:deep(img) { max-width: 100%; border-radius: 8rpx; }
}
.bottom-bar {
position: fixed; bottom: 0; left: 0; right: 0;
background-color: #fff; padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
z-index: 100;
box-shadow: 0 -4rpx 20rpx rgba(0,0,0,0.08);
.submit-btn {
background-color: #fa6400; color: #fff; font-weight: bold;
border-radius: 44rpx; height: 88rpx; line-height: 88rpx;
font-size: 30rpx; margin: 0;
&::after { border: none; }
}
}
</style>