216 lines
7.6 KiB
Plaintext
216 lines
7.6 KiB
Plaintext
<template>
|
|
<view class="points-mall-page">
|
|
<!-- 全新方案:纯 CSS 手动构建的骨架屏 -->
|
|
<view v-if="loading" class="skeleton-wrapper">
|
|
<view class="skeleton-item skeleton-rect" style="height: 300rpx; margin: 24rpx; border-radius: 16rpx;"></view>
|
|
<view class="skeleton-content">
|
|
<view class="skeleton-left-panel">
|
|
<view v-for="i in 6" :key="i" class="skeleton-item skeleton-text" style="width: 80%; height: 60rpx; margin-bottom: 50rpx;"></view>
|
|
</view>
|
|
<view class="skeleton-right-panel">
|
|
<view v-for="i in 4" :key="i" class="skeleton-card">
|
|
<view class="skeleton-item skeleton-rect" style="width: 160rpx; height: 160rpx;"></view>
|
|
<view style="flex:1; margin-left: 24rpx;">
|
|
<view class="skeleton-item skeleton-text" style="width: 90%; height: 30rpx;"></view>
|
|
<view class="skeleton-item skeleton-text" style="width: 60%; height: 32rpx; margin-top: 40rpx;"></view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 页面实际内容 -->
|
|
<view v-else class="page-content">
|
|
<!-- 1. 顶部轮播图 (原生 <swiper> 实现) -->
|
|
<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 swiperList" :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">
|
|
<view class="dot" :class="{ active: index === swiperCurrent }" v-for="(item, index) in swiperList" :key="index"></view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 2. 主体内容:左右联动 -->
|
|
<view class="main-content">
|
|
<!-- 左侧分类栏 -->
|
|
<scroll-view class="left-panel" scroll-y>
|
|
<view
|
|
class="category-item"
|
|
:class="{ active: currentCategory === index }"
|
|
v-for="(cat, index) in categories"
|
|
:key="cat.id"
|
|
@click="selectCategory(index)"
|
|
>
|
|
<text class="name">{{ cat.name }}</text>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<!-- 右侧商品列表 -->
|
|
<scroll-view class="right-panel" scroll-y>
|
|
<view class="product-list">
|
|
<view class="product-card" v-for="product in products" :key="product.id" @click="Service.GoPage('/pages/goods/integralGoods')">
|
|
<view class="image-placeholder product-image">
|
|
<image :src="product.img" style="width: 100%; height: 100%; border-radius: 20rpx;" mode=""></image>
|
|
</view>
|
|
<view class="product-info">
|
|
<text class="name">{{ product.name }}</text>
|
|
<view class="price-line">
|
|
<text class="points">{{ product.points }} 积分</text>
|
|
<text class="original-price" v-if="product.originalPrice">+ ¥{{ product.originalPrice }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
</view>
|
|
</view>
|
|
<up-loadmore status="nomore" nomoreText="没有更多商品了"></up-loadmore>
|
|
</scroll-view>
|
|
</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>(true);
|
|
const currentCategory = ref(0);
|
|
const swiperCurrent = ref(0);
|
|
|
|
// 轮播图数据
|
|
const swiperList = reactive([
|
|
'/static/dele/dele1.jpg',
|
|
'/static/dele/dele2.jpg',
|
|
'/static/dele/dele3.png',
|
|
]);
|
|
|
|
// 分类数据
|
|
const categories = reactive([
|
|
{ id: 1, name: '热门兑换' }, { id: 2, name: '生活家居' }, { id: 3, name: '数码家电' },
|
|
{ id: 4, name: '美妆个护' }, { id: 5, name: '食品饮料' }, { id: 6, name: '虚拟卡券' },
|
|
]);
|
|
|
|
// 商品数据
|
|
const products = reactive([
|
|
{ id: 101, name: '品牌充电宝 10000mAh 金属外壳 超薄便携', img:'/static/dele/dele1.jpg', points: 2000, originalPrice: 19.9 },
|
|
{ id: 102, name: '声波震动电动牙刷 智能计时', img:'/static/dele/dele2.jpg', points: 5000 },
|
|
{ id: 103, name: '知名视频网站月度会员卡 直充', img:'/static/dele/dele3.png', points: 1500, originalPrice: 5 },
|
|
{ id: 104, name: '“天命打工人”限定版帆布袋', img:'/static/dele/dele4.jpg', points: 800 },
|
|
]);
|
|
|
|
const selectCategory = (index: number) => {
|
|
if (currentCategory.value === index) return;
|
|
currentCategory.value = index;
|
|
console.log(`切换到分类: ${categories[index].name}`);
|
|
};
|
|
|
|
onLoad(() => {
|
|
setTimeout(() => { loading.value = false; }, 1500);
|
|
});
|
|
onShow(() => {});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
/* 骨架屏样式 */
|
|
.skeleton-wrapper {
|
|
background-color: #f7f7f7;
|
|
.skeleton-content { display: flex; }
|
|
.skeleton-left-panel { width: 180rpx; padding: 30rpx 20rpx; background: #f7f7f7; }
|
|
.skeleton-right-panel { flex: 1; padding: 30rpx; background: #fff; }
|
|
.skeleton-card { display: flex; align-items: center; gap: 24rpx; padding-bottom: 30rpx; margin-bottom: 30rpx; border-bottom: 1rpx solid #f0f0f0;}
|
|
}
|
|
|
|
.points-mall-page {
|
|
background-color: #f7f7f7; height: 100vh;
|
|
display: flex; flex-direction: column;
|
|
}
|
|
|
|
.swiper-section {
|
|
padding: 24rpx;
|
|
position: relative;
|
|
.swiper-container {
|
|
height: 300rpx;
|
|
border-radius: 16rpx;
|
|
overflow: hidden;
|
|
}
|
|
.swiper-item {
|
|
width: 100%; height: 100%;
|
|
.swiper-image { width: 100%; height: 100%; }
|
|
}
|
|
.swiper-dots {
|
|
position: absolute;
|
|
bottom: 40rpx; left: 50%;
|
|
transform: translateX(-50%);
|
|
display: flex; gap: 12rpx;
|
|
.dot {
|
|
width: 12rpx; height: 12rpx;
|
|
border-radius: 50%; background-color: rgba(255, 255, 255, 0.5);
|
|
transition: all 0.3s;
|
|
&.active { width: 30rpx; background-color: #fff; }
|
|
}
|
|
}
|
|
}
|
|
|
|
.main-content {
|
|
flex: 1; display: flex; overflow: hidden;
|
|
}
|
|
|
|
.left-panel {
|
|
width: 180rpx; background-color: #f7f7f7; height: 100%;
|
|
.category-item {
|
|
padding: 30rpx 20rpx; font-size: 28rpx; color: #666;
|
|
text-align: center; position: relative;
|
|
&.active {
|
|
background-color: #fff; color: #333; font-weight: bold;
|
|
&::before {
|
|
content: ''; position: absolute; left: 0; top: 50%;
|
|
transform: translateY(-50%); width: 8rpx; height: 40rpx;
|
|
background-color: #fa6400;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.right-panel {
|
|
flex: 1; background-color: #fff; height: 100%; padding: 30rpx;
|
|
.product-list { display: flex; flex-direction: column; gap: 30rpx; }
|
|
.product-card {
|
|
display: flex; gap: 24rpx; align-items: center;
|
|
border-bottom: 1rpx solid #e2e2e2;
|
|
padding-bottom: 10rpx;
|
|
.product-image {
|
|
width: 160rpx; height: 160rpx;
|
|
border-radius: 12rpx; flex-shrink: 0;
|
|
}
|
|
.product-info {
|
|
flex: 1; min-width: 0;
|
|
.name {
|
|
font-size: 28rpx; color: #333; font-weight: 500;
|
|
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
|
|
overflow: hidden; text-overflow: ellipsis;
|
|
}
|
|
.price-line {
|
|
margin-top: 20rpx; display: flex; align-items: baseline;
|
|
.points { font-size: 32rpx; font-weight: bold; color: #fa6400; }
|
|
.original-price { font-size: 22rpx; color: #999; margin-left: 8rpx; }
|
|
}
|
|
}
|
|
.exchange-btn {
|
|
background-color: #fa6400; color: #fff;
|
|
border-radius: 30rpx; font-size: 24rpx;
|
|
padding: 10rpx 24rpx; margin: 0;
|
|
height: fit-content; line-height: 1.5;
|
|
&::after { border: none; }
|
|
}
|
|
}
|
|
}
|
|
</style> |