فهرست منبع

feat:积分商城(商品列表搜索框样式,吸顶和未吸顶样式调整)

xyh 5 ماه پیش
والد
کامیت
3cd144297c
4فایلهای تغییر یافته به همراه329 افزوده شده و 145 حذف شده
  1. 87 2
      src/api/points.js
  2. 174 138
      src/points/components/product-list/product-list.vue
  3. 1 2
      src/points/components/task-list/task-list.vue
  4. 67 3
      src/points/home/index.vue

+ 87 - 2
src/api/points.js

@@ -1,10 +1,95 @@
 import request from "@/utils/request.js";
 
-// 签到任务获取
-export function orderDeatails(data) {
+// 积分商品列表
+export function getPointShopList(data) {
+    // 模拟数据返回
+    return new Promise((resolve, reject) => {
+        setTimeout(() => {
+            const mockData = {
+                code: 200,
+                message: 'success',
+                data: {
+                    list: [
+                        {
+                            id: 1,
+                            name: '广誉源会员定制玻璃杯',
+                            price: '10元+1000积分',
+                            value: '100',
+                            sales: 10,
+                            image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
+                        },
+                        {
+                            id: 2,
+                            name: '广誉源会员定制保温杯',
+                            price: '20元+2000积分',
+                            value: '200',
+                            sales: 20,
+                            image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
+                        },
+                        {
+                            id: 3,
+                            name: '广誉源会员定制雨伞',
+                            price: '15元+1500积分',
+                            value: '150',
+                            sales: 15,
+                            image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
+                        },
+                        {
+                            id: 4,
+                            name: '广誉源会员定制笔记本',
+                            price: '5元+500积分',
+                            value: '50',
+                            sales: 5,
+                            image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
+                        },
+                        {
+                            id: 6,
+                            name: '广誉源会员定制玻璃杯',
+                            price: '10元+1000积分',
+                            value: '100',
+                            sales: 10,
+                            image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
+                        },
+                        {
+                            id: 7,
+                            name: '广誉源会员定制保温杯',
+                            price: '20元+2000积分',
+                            value: '200',
+                            sales: 20,
+                            image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
+                        },
+                        {
+                            id: 8,
+                            name: '广誉源会员定制雨伞',
+                            price: '15元+1500积分',
+                            value: '150',
+                            sales: 15,
+                            image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
+                        },
+                        {
+                            id: 9,
+                            name: '广誉源会员定制笔记本',
+                            price: '5元+500积分',
+                            value: '50',
+                            sales: 5,
+                            image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
+                        }
+                    ],
+                    total: 9,
+                    page: data.page || 1,
+                    pageSize: data.pageSize || 10
+                }
+            };
+            resolve(mockData);
+        }, 800);
+    });
+    
+    // 真实API调用
+    /*
     return request({
         method: 'get',
         url: '/api/order/v1/wx/getOrder',
         data
     });
+    */
 }

+ 174 - 138
src/points/components/product-list/product-list.vue

@@ -1,9 +1,10 @@
 <template>
   <view class="product-list-container">
+    <u-sticky bgColor="#ffffff">
     <!-- 商品列表头部 -->
     <view class="product-header">
-      <view class="title-text"><text>精选好物</text>兑换</view>
-      <u-search placeholder="日照香炉生紫烟" v-model="keyword" :showAction="false"></u-search>
+      <view class="title-text" :class="{ 'hide': isSticky }"><text>精选好物</text>兑换</view>
+      <u-search placeholder="搜索" v-model="keyword" :showAction="false" :class="{ 'expand': isSticky }"></u-search>
     </view>
     
     <!-- 分类标签 -->
@@ -22,7 +23,7 @@
             color: '#606266',
             transform: 'scale(1)'
         }"
-      itemStyle="padding:0 45rpx; height: 72rpx;font-size:28rpx"
+      itemStyle="padding:0 43rpx; height: 72rpx;font-size:28rpx"
       class="category-tabs"
     ></u-tabs>
     
@@ -35,46 +36,58 @@
         @click="switchSort(sort.key)"
       >
         <text :class="['sort-text', { active: activeSort === sort.key }]">{{ sort.name }}</text>
-        <view v-if="['price','sales'].includes(sort.key)">
-          <ImageItem src="/static/points/arrow-up.png" v-if="sortDirection === 'asc'"></ImageItem>
-          <ImageItem src="/static/points/arrow-down.png" v-else-if="sortDirection === 'desc'"></ImageItem>
+        <view v-if="['price','sales'].includes(sort.key)" style="margin-top: -8rpx;">
+          <ImageItem src="/static/points/arrow-up.png" v-if="activeSort === sort.key && sortDirection === 'asc'"></ImageItem>
+          <ImageItem src="/static/points/arrow-down.png" v-else-if="activeSort === sort.key && sortDirection === 'desc'"></ImageItem>
           <ImageItem src="/static/points/details.png" v-else></ImageItem>
         </view>
       </view>
     </view>
-    
+    </u-sticky>
     <!-- 商品列表 -->
-      <view class="product-grid">
-        <view 
-          v-for="(product, index) in products" 
-          :key="index"
-          class="product-item">
-          <view class="product-image">
-            <ImageItem :src="product.image" mode="aspectFill"/>
-          </view>
-          <view class="product-info">
-            <u--text class="product-name" :lines="1" :text="product.name"></u--text>
-            <text class="product-price">{{ product.price }}</text>
-            <view class="product-details">
-              <view class="product-detail">
-                <text class="product-value">价值{{ product.value }}元</text>
-                <text class="product-sales">销量{{ product.sales }}</text>
-              </view>
-              <button class="exchange-btn" @click="handleExchange(product)">
-                兑换
-              </button>
+    <u-loading-icon text="加载中" textSize="18" v-if="status === 'loading' && products.length <= 0" style="margin-top: 200rpx;"/>
+    <view class="product-grid" v-else-if="products.length > 0">
+      <view class="product-item" v-for="(product, index) in products" :key="index">
+        <view class="product-image">
+          <ImageItem :src="product.image" mode="aspectFill"/>
+        </view>
+        <view class="product-info">
+          <u--text class="product-name" :lines="1" :text="product.name"></u--text>
+          <text class="product-price">{{ product.price }}</text>
+          <view class="product-details">
+            <view class="product-detail">
+              <text class="product-value">价值{{ product.value }}元</text>
+              <text class="product-sales">销量{{ product.sales }}</text>
             </view>
+            <button class="exchange-btn" @click="handleExchange(product)">
+              兑换
+            </button>
           </view>
         </view>
       </view>
+    </view>
+    <u-loadmore :status="status" loading-text="努力加载中" nomore-text="没有更多了" lineColor="#E6E8EB" v-if="products.length > 0"/>
+    <u-empty
+        v-if="products.length <= 0 && status !== 'loading'"
+        icon="car-fill"
+        text="暂无积分商品"
+    >
+    </u-empty>
   </view>
 </template>
 
 <script>
 import ImageItem from "@/components/swiper/components/image.vue";
-
+import {getPointShopList} from '@/api/points'
 export default {
   components: {ImageItem},
+  props: {
+    // 从父组件传递的滚动距离
+    scrollTop: {
+      type: Number,
+      default: 0
+    }
+  },
   data() {
     return {
       // 搜索关键词
@@ -98,128 +111,132 @@ export default {
       activeSort: '综合',
       sortDirection: '',
       // 商品数据
-      products: [
-        {
-          id: 1,
-          name: '广誉源会员定制玻璃杯广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 2,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 3,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 4,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 5,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 6,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 7,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 8,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 9,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 10,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 11,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        },
-        {
-          id: 12,
-          name: '广誉源会员定制玻璃杯',
-          price: '10元+1000积分',
-          value: '100',
-          sales: 10,
-          image: 'https://test.baoxianzhanggui.com/nightFragrance/profile/upload/2025/01/03/b43f6087c815cdab8828eb68529d96bc73203b941ab71e-xrpfmn_fw1200webp_20250103175413A002.png'
-        }
-      ],
+      products:[],
       // 分页数据
       page: 1,
       pageSize: 10,
+      status:'more',
+      hasMore: true,
+      // 吸顶状态
+      isSticky: false,
+      // 吸顶元素的初始位置
+      stickyTop: 0
     }
   },
-  computed: {
-    activeCategoryIndex() {
-      return this.categories.findIndex(item => item.key === this.activeCategory)
+  mounted() {
+    this.loadData()
+    // 延迟获取吸顶元素的初始位置,确保DOM已经渲染完成
+    this.$nextTick(() => {
+      this.getStickyTop()
+    })
+  },
+  watch: {
+    // 监听滚动距离的变化
+    scrollTop(newVal) {
+      // 判断是否进入吸顶状态
+      this.isSticky = newVal >= this.stickyTop
     }
   },
   methods: {
+    // 获取吸顶元素的初始位置
+    getStickyTop() {
+      const query = uni.createSelectorQuery().in(this)
+      query.select('.product-header').boundingClientRect(data => {
+        if (data) {
+          this.stickyTop = data.top
+        }
+      }).exec()
+    },
+    // 加载商品数据
+    fetchProducts(page) {
+      return getPointShopList({
+        page: page,
+        pageSize: this.pageSize,
+        category: this.activeCategory,
+        sort: this.activeSort,
+        sortDirection: this.sortDirection
+      })
+    },
+    // 加载初始数据
+    loadData() {
+      this.status = 'loading'
+      this.fetchProducts(1).then(res => {
+        console.log(res)
+        if (res.code === 200) {
+          this.products = res.data.list
+          this.hasMore = res.data.list.length === this.pageSize
+          this.status = this.hasMore ? 'more' : 'nomore'
+        } else {
+          this.status = 'error'
+        }
+      }).catch(err => {
+        console.error('加载商品列表失败:', err)
+        this.status = 'error'
+      })
+    },
     // 处理分类切换
-    handleCategoryChange(index) {
-
+    handleCategoryChange(data) {
+      this.activeCategory = data.key
+      //重置页码
+      this.page = 1
+      // 等待DOM更新后再加载数据
+      this.$nextTick(() => {
+        this.loadData()
+      })
     },
     // 切换排序
     switchSort(sort) {
-
+      if (this.activeSort === sort) {
+        // 如果点击的是当前排序,切换排序方向
+        this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc'
+      } else {
+        // 如果点击的是新排序,设置默认排序方向
+        this.activeSort = sort
+        // 价格和销量默认排序方向为asc
+        if (['price', 'sales'].includes(sort)) {
+          this.sortDirection = 'asc'
+        } else {
+          this.sortDirection = ''
+        }
+      }
+      // 重置页码
+      this.page = 1
+      // 等待DOM更新后再加载数据
+      this.$nextTick(() => {
+        this.loadData()
+      })
     },
     // 处理兑换
     handleExchange(product) {
       console.log('兑换商品:', product)
+    },
+    // 加载更多
+    loadMore() {
+      if (this.status === 'loading' || !this.hasMore) return
+      
+      this.status = 'loading'
+      this.page++
+      
+      this.fetchProducts(this.page).then(res => {
+        if (res.code === 200) {
+          const newProducts = res.data.list
+          this.products = [...this.products, ...newProducts]
+          this.hasMore = newProducts.length === this.pageSize
+          this.status = this.hasMore ? 'more' : 'nomore'
+        } else {
+          this.status = 'error'
+        }
+      }).catch(err => {
+        console.error('加载更多商品失败:', err)
+        this.status = 'error'
+      })
+    },
+  },
+  computed: {
+    activeCategoryIndex() {
+      return this.categories.findIndex(item => item.key === this.activeCategory)
     }
-  }
+  },
 }
 </script>
 
@@ -228,13 +245,15 @@ export default {
   width: 750rpx;
   background: #FFFFFF;
   border-radius: 20rpx 20rpx 0 0;
-
+  padding-bottom: 32rpx;
   .product-header {
     display: flex;
     justify-content: space-between;
     align-items: center;
     padding: 24rpx 32rpx 0 32rpx;
     background-color: #fff;
+    transition: all 0.3s ease;
+    height: 90rpx;
     .title-text {
       font-size: 32rpx;
       font-weight: 600;
@@ -242,12 +261,30 @@ export default {
       margin-right: 22rpx;
       text{
         color: #20CAC2;
+        margin-right: 4rpx;
+      }
+      transition: all 0.3s ease;
+      &.hide {
+        opacity: 0;
+        transform: translateX(-20rpx);
+        width: 0;
+        margin-right: 0;
+        overflow: hidden;
       }
     }
     
     .search-icon {
       margin-right: 8rpx;
     }
+    
+    :deep(.u-search) {
+      flex: 1;
+      max-width: 300rpx;
+      transition: all 0.3s ease;
+      &.expand {
+        max-width: 100%;
+      }
+    }
   }
   
   .category-tabs {
@@ -269,7 +306,7 @@ export default {
       flex: 1;
       
       .sort-text {
-        font-size: 24rpx;
+        font-size: 28rpx;
         color: #666;
         
         &.active {
@@ -290,10 +327,8 @@ export default {
     grid-template-columns: repeat(2, 1fr);
     grid-gap: 24rpx;
     padding: 24rpx 32rpx;
-    
     .product-item {
       width: 324rpx;
-      height: 440rpx;
       background-color: #fff;
       border-radius: 12rpx;
       overflow: hidden;
@@ -318,7 +353,7 @@ export default {
           font-size: 28rpx;
           color: #333333;
           display: block;
-          margin-bottom: 6rpx;
+          margin-bottom: 16rpx!important;
         }
         
         .product-price {
@@ -327,7 +362,7 @@ export default {
           font-size: 32rpx;
           color: #F53E54;
           display: block;
-          margin-bottom: 8rpx;
+          margin-bottom: 16rpx;
         }
         .product-details{
           display: flex;
@@ -338,6 +373,7 @@ export default {
               display: block;
               font-size: 24rpx;
               color: #999999;
+              margin-bottom: 18rpx;
             }
 
             .product-sales {

+ 1 - 2
src/points/components/task-list/task-list.vue

@@ -102,7 +102,7 @@ export default {
       display: flex;
       justify-content: space-between;
       align-items: center;
-      margin-bottom: 15rpx;
+      margin-bottom: 32rpx;
       .task-item-left {
         display: flex;
         align-items: center;
@@ -150,7 +150,6 @@ export default {
       
       .task-item-right {
         .task-btn {
-          width: 126rpx;
           height: 48rpx;
           background: #03C1B8;
           border-radius: 98rpx;

+ 67 - 3
src/points/home/index.vue

@@ -12,10 +12,71 @@ export default {
   data() {
     return {
       totalPoints: 999,
-      monthlyPoints: 888
+      monthlyPoints: 888,
+      // 滚动距离
+      scrollTop: 0
+    }
+  },
+  mounted() {
+    // 在H5端添加滚动事件监听器
+    if (process.env.UNI_PLATFORM === 'h5') {
+      // 使用this.$el获取当前组件的根元素
+      const homeEl = this.$el
+      if (homeEl) {
+        homeEl.addEventListener('scroll', this.handleScroll)
+      }
+    } else {
+      // 在非H5端监听页面滚动事件
+      uni.onPageScroll(this.handlePageScroll)
+    }
+  },
+  beforeUnmount() {
+    // 移除滚动事件监听器
+    if (process.env.UNI_PLATFORM === 'h5') {
+      const homeEl = this.$el
+      if (homeEl) {
+        homeEl.removeEventListener('scroll', this.handleScroll)
+      }
+    } else {
+      // 移除页面滚动事件监听
+      uni.offPageScroll(this.handlePageScroll)
     }
   },
   methods: {
+    handleScroll() {
+      const homeEl = this.$el
+      if (homeEl) {
+        const scrollTop = homeEl.scrollTop
+        // 更新滚动距离
+        this.scrollTop = scrollTop
+        const scrollHeight = homeEl.scrollHeight
+        const clientHeight = homeEl.clientHeight
+        // 当滚动到距离底部50px以内时,触发加载更多
+        if (scrollTop + clientHeight >= scrollHeight - 50) {
+          this.reachBottom()
+        }
+      }
+    },
+    // 处理页面滚动事件(非H5端)
+    handlePageScroll(e) {
+      const scrollTop = e.scrollTop
+      // 更新滚动距离
+      this.scrollTop = scrollTop
+      // 当滚动到距离底部50px以内时,触发加载更多
+      const homeEl = this.$el
+      if (homeEl) {
+        const scrollHeight = homeEl.scrollHeight
+        const clientHeight = homeEl.clientHeight
+        if (scrollTop + clientHeight >= scrollHeight - 50) {
+          this.reachBottom()
+        }
+      }
+    },
+    reachBottom() {
+      if (this.$refs.productRef) {
+        this.$refs.productRef.loadMore()
+      }
+    },
     handleSign(index) {
       // 处理签到逻辑
       console.log('签到:', index)
@@ -53,13 +114,16 @@ export default {
       <TaskList @task="handleTask" @moreTasks="handleMoreTasks"/>
     </view>
     <!-- 商品列表组件 -->
-    <ProductList />
+    <ProductList ref="productRef" :scrollTop="scrollTop" />
   </view>
 </template>
 
 <style lang="scss" scoped>
 .points-home{
-  min-height: 100vh;
+  height: 100vh;
+  overflow-y: auto;
+  -webkit-overflow-scrolling: touch;
+  position: relative;
 }
 .points-task {
   background-image: url("@/static/points/homeBg.png");