绿满眶商城微信小程序-uniapp
pages/mine/myCollect/myCollect.vue
@@ -10,103 +10,147 @@
      </view>
      <!-- 视频列表 -->
      <view class="activity-list" >
      <view class="activity-list">
         <view v-if="currentTab === 0">
            <view v-if="signedActivities.length > 0">
               <view v-for="(item, idx) in signedActivities" :key="idx" class="activity-item">
                  <!-- 封面区域 -->
                  <block v-if="item.coverType === '图片' || item.coverType === '视频'">
                     <image :src="getPreviewUrl(item.cover)" mode="aspectFill" class="activity-cover" />
                  </block>
                  <block v-if="item.coverType === '文字'">
                     <view class="activity-cover">{{ item.cover }}</view>
                  </block>
            <scroll-view scroll-y class="activity-list" style="height: 100vh;" @scrolltolower="loadMore"
               :lower-threshold="100">
               <view v-if="videoCollects.length > 0">
                  <view v-for="(item, idx) in videoCollects" :key="idx" class="video-item">
                     <!-- 视频封面+播放按钮 -->
                     <view class="video-cover-container">
                        <image :src="item.coverUrl" mode="aspectFill" class="video-cover" />
                        <view class="play-icon">
                           <u-icon name="play-circle-fill" size="60" color="#fff"></u-icon>
                        </view>
                        <view class="video-duration" v-if="item.duration">{{ item.duration }}</view>
                     </view>
                  <!-- 活动信息 -->
                  <view class="activity-info">
                     <view class="activity-title">{{ item.activityName }}</view>
                     <view class="activity-meta">
                        <text class="activity-time">{{ item.startTime }} - {{ item.endTime }}</text>
                        <text class="activity-location">{{ item.activityLocation || '暂无' }}</text>
                     <!-- 视频信息 -->
                     <view class="video-info">
                        <view class="video-title">{{ item.authorName || '未知作者' }}</view>
                        <view class="video-meta">
                           <text class="video-weight" v-if="item.weight > 0">
                              <u-icon name="thumb-up-fill" size="24" color="#999"></u-icon>
                              {{ item.weight }}
                           </text>
                        </view>
                     </view>
                     <!-- 操作按钮 -->
                     <view class="video-actions">
                        <button class="cancel-btn" @click.stop="handleCancelCollection(item,'video')">
                           取消收藏
                        </button>
                     </view>
                  </view>
                  <!-- 操作区域 -->
                  <view class="action-container">
                     <button class="cancel-btn" @click="handleCancelCollection(item)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </view>
               </view>
            </view>
               <view v-else class="empty-tip">
                  <text>暂无收藏视频</text>
               </view>
               <view class="load-more">
                  <u-loadmore v-if="videoCollects.length > 0"
                     :status="loading ? 'loading' : noMore ? 'nomore' : 'loadmore'" :load-text="{
                  loadmore: '上拉加载更多',
                  loading: '正在加载',
                  nomore: '没有更多了'
                }" />
               </view>
            </scroll-view>
         </view>
         <view v-if="currentTab === 1">
            <!-- 已结束活动列表 -->
            <view v-if="endedActivities.length > 0">
               <view v-for="(item, idx) in endedActivities" :key="idx" class="activity-item">
                  <!-- 封面区域 -->
                  <block v-if="item.coverType === '图片' || item.coverType === '视频'">
                     <image :src="getPreviewUrl(item.cover)" mode="aspectFill" class="activity-cover" />
                  </block>
                  <block v-if="item.coverType === '文字'">
                     <view class="activity-cover">{{ item.cover }}</view>
                  </block>
            <scroll-view scroll-y class="activity-list" style="height: 100vh;" @scrolltolower="loadMore"
               :lower-threshold="100">
               <view v-if="goodsCollects.length > 0">
                  <view v-for="(item, idx) in goodsCollects" :key="idx" class="activity-item">
                     <!-- 封面区域 -->
                     <block>
                        <image :src="item.original" mode="aspectFill" class="activity-cover" />
                     </block>
                  <!-- 活动信息 -->
                  <view class="activity-info">
                     <view class="activity-title">{{ item.activityName }}</view>
                     <view class="activity-meta">
                        <text class="activity-time">{{ item.startTime }} - {{ item.endTime }}</text>
                        <text class="activity-location">{{ item.activityLocation || '暂无' }}</text>
                     <!-- 活动信息 -->
                     <view class="activity-info">
                        <view class="activity-title">{{ item.goodsName }}</view>
                        <view class="activity-meta">
                           <text class="activity-time">价格:{{ item.price }}元</text>
                           <text class="activity-location">{{ item.storeName || '暂无' }}</text>
                        </view>
                     </view>
                  </view>
                  <!-- 操作区域 -->
                  <view class="action-container">
                     <button class="cancel-btn" @click="handleCancelCollection(item)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </view>
                     <!-- 操作区域 -->
                     <view class="action-container">
                        <button class="cancel-btn" @click="handleCancelCollection(item,'goods')"
                           hover-class="cancel-btn-hover">
                           取消收藏
                        </button>
                     </view>
                  </view>
               </view>
            </view>
               <view v-else class="empty-tip">
                  <text>暂无收藏商品</text>
               </view>
               <view class="load-more">
                  <u-loadmore v-if="goodsCollects.length > 0"
                     :status="loading ? 'loading' : noMore ? 'nomore' : 'loadmore'" :load-text="{
                  loadmore: '上拉加载更多',
                  loading: '正在加载',
                  nomore: '没有更多了'
                }" />
               </view>
            </scroll-view>
         </view>
         <view v-if="currentTab === 2">
            <!-- 已取消活动列表 -->
            <view v-if="canceledActivities.length > 0">
               <view v-for="(item, idx) in endedActivities" :key="idx" class="activity-item">
                  <!-- 封面区域 -->
                  <block v-if="item.coverType === '图片' || item.coverType === '视频'">
                     <image :src="getPreviewUrl(item.cover)" mode="aspectFill" class="activity-cover" />
                  </block>
                  <block v-if="item.coverType === '文字'">
                     <view class="activity-cover">{{ item.cover }}</view>
                  </block>
                  <!-- 活动信息 -->
                  <view class="activity-info">
                     <view class="activity-title">{{ item.activityName }}</view>
                     <view class="activity-meta">
                        <text class="activity-time">{{ item.startTime }} - {{ item.endTime }}</text>
                        <text class="activity-location">{{ item.activityLocation || '暂无' }}</text>
            <scroll-view scroll-y class="activity-list" style="height: 80vh;" @scrolltolower="loadMore"
               :lower-threshold="100">
               <view v-if="activityCollects.length > 0">
                  <view v-for="(item, idx) in activityCollects" :key="idx" class="activity-item">
                     <!-- 封面区域 -->
                     <block v-if="item.coverType === '图片' || item.coverType === '视频'">
                        <image :src="item.cover" mode="aspectFill" class="activity-cover" />
                     </block>
                     <block v-if="item.coverType === '文字'">
                        <view class="activity-cover  text-cover">{{ item.cover }}</view>
                     </block>
                     <!-- 活动信息 -->
                     <view class="activity-info">
                        <view class="activity-title">{{ item.activityName }}</view>
                        <view class="activity-meta">
                           <text class="activity-time">{{ item.startTime }}</text>
                           <text class="activity-time"> {{ item.endTime }}</text>
                           <text class="activity-location">{{ item.activityLocation || '暂无' }}</text>
                        </view>
                     </view>
                     <!-- 操作区域 -->
                     <view class="action-container">
                        <button class="cancel-btn" @click="handleCancelCollection(item,'activity')"
                           hover-class="cancel-btn-hover">
                           取消收藏
                        </button>
                     </view>
                  </view>
                  <!-- 操作区域 -->
                  <view class="action-container">
                     <button class="cancel-btn" @click="handleCancelCollection(item)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </view>
               </view>
            </view>
               <view v-else class="empty-tip">
                  <text>暂无收藏活动</text>
               </view>
               <view class="load-more">
                  <u-loadmore v-if="activityCollects.length > 0"
                     :status="loading ? 'loading' : noMore ? 'nomore' : 'loadmore'" :load-text="{
                  loadmore: '上拉加载更多',
                  loading: '正在加载',
                  nomore: '没有更多了'
                }" />
               </view>
               <view style="height: 150rpx"></view>
            </scroll-view>
         </view>
@@ -120,88 +164,300 @@
</template>
<script>
   import ULoadmore from '@/uview-components/uview-ui/components/u-loadmore/u-loadmore.vue'
   import UImage from '@/uview-components/uview-ui/components/u-image/u-image.vue';
   import {
      getMyActivityList,
      activityCancel
   } from '@/api/activity.js'
   import {
      getPreviewUrl
      getFilePreviewUrl
   } from '@/api/common.js'
   import {
      changeCollect,
      getMyCollectList
   } from '@/api/collect.js'
   import {
      ifError
   } from 'assert'
   export default {
      components: {
         UImage,
         ULoadmore
      },
      data() {
         return {
            total: 0,
            loading: false,
            noMore: {
               video: false,
               goods: false,
               activity: false
            },
            currentTab: 0, // 当前选中的tab索引
            tabs: ['视频', '商品', '活动'],
            //
            //
            videoCollects: [], // 收藏视频列表
            storeCollects: [], // 收藏商品列表
            goodsCollects: [], // 收藏商品列表
            activityCollects: [], // 收藏活动列表
            query: {
               id: '',
               status: '',
               cancel: false,
            collectForm: {
               collectType: '',
               refId: '',
            },
            query: {
               type: 'video',
               pageNumber: 1,
               pageSize: 5,
            }
         }
      },
      onLoad(){
      onLoad() {
         this.currentTab = 0;
         //TODO 未登录需要id,测试用写死\
         this.switchTab(this.currentTab);
         this.getintit()
      },
      methods: {
         handleCancelCollection(id) {
         /**
          * 下拉刷新时
          */
         onPullDownRefresh() {
            this.currentTab = 0;
            this.query.pageNumber = 1; // 重置页码
            this.noMore = false;
            this.videoCollects = [];
            this.goodsCollects = []; // 收藏商品列表
            this.activityCollects = []; // 收藏活动列表// 清空数据
            this.getintit();
         },
         getPreviewUrl(params) {
            // return getPreviewUrl(params);
            return '';
         loadMore() {
            this.loading = true;
            this.query.pageNumber += 1;
            // 延迟执行让UI有反应时间
            setTimeout(() => {
               this.query.pageNumber += 1;
               this.getintit();
            }, 300);
         },
         handleCancelCollection(item, type) {
            console.log(item)
            this.collectForm.collectType = type;
            this.collectForm.refId = item.id;
            changeCollect(this.collectForm).then(res => {
               if (res.statusCode === 200) {
                  uni.showToast({
                     title: res.data.msg, // 提示文字
                     icon: 'none', // 图标类型(success/loading/none)
                     mask: true // 是否显示透明蒙层(防止触摸穿透)
                  });
                  this.getintit();
               }
            })
         },
         getUrl(params) {
            getFilePreviewUrl(params).then(res => {
               return res.data.data
            })
         },
         // 切换tab
         switchTab(index) {
            if (this.currentTab !== index) {
               this.currentTab = index
               //切换时页码归0
               this.query.pageNumber = 0;
               // 清空数据
               this.videoCollects = [];
               this.goodsCollects = [];
               this.activityCollects = [];
               // 实际项目中可以在这里添加加载数据的逻辑
               if (this.currentTab === 0) {
                  //加载视频列表
                  this.getMyCollectionVideoList();
               } else if (this.currentTab === 1) {
                  //加载商品列表
                  this.getMyCollectionStoreList();
               } else if (this.currentTab === 2) {
                  //加载活动列表
                  this.getMyCollectActivityList();
               }
               this.getintit()
            }
         },
         async getintit() {
            uni.showLoading({
               title: '加载中'
            });
            if (this.currentTab === 0) {
               this.query.type = 'video';
               getMyCollectList(this.query).then(res => {
                  uni.hideLoading();
                  this.loading = false;
                  if (res.statusCode === 200) {
                     const newData = res.data.data
                     this.total = res.data.total || 0;
                     // 追加或替换数据
                     this.videoCollects = this.query.pageNumber === 1 ?
                        newData :
                        [...this.videoCollects, ...newData];
                     // 判断是否还有更多数据
                     this.noMore = newData.length < this.query.pageSize ||
                        this.videoCollects.length >= this.total;
                  }
               })
            } else if (this.currentTab === 1) {
               this.query.type = 'goods';
               getMyCollectList(this.query).then(res => {
                  uni.hideLoading();
                  this.loading = false;
                  if (res.statusCode === 200) {
                     const newData = res.data.data
                     this.total = res.data.total || 0;
                     this.goodsCollects = this.query.pageNumber === 1 ?
                        newData :
                        [...this.goodsCollects, ...newData];
                     // 判断是否还有更多数据
                     this.noMore = newData.length < this.query.pageSize ||
                        this.goodsCollects.length >= this.total;
                  }
               })
            } else if (this.currentTab === 2) {
               this.query.type = 'activity';
               getMyCollectList(this.query).then(res => {
                  uni.hideLoading();
                  this.loading = false;
                  if (res.statusCode === 200) {
                     const newData = res.data.data
                     this.total = res.data.total || 0;
                     this.activityCollects = this.query.pageNumber === 1 ?
                        newData :
                        [...this.activityCollects, ...newData];
                     this.noMore = newData.length < this.query.pageSize ||
                        this.activityCollects.length >= this.total;
                  }
               })
            }
         },
         getMyCollectionStoreList() {
            uni.showLoading({
               title: '加载中'
            });
            uni.hideLoading();
         },
         getMyCollectionVideoList() {
            uni.showLoading({
               title: '加载中'
            });
            uni.hideLoading();
         },
         getMyCollectActivityList() {
            uni.showLoading({
               title: '加载中'
            });
            uni.hideLoading();
         },
         }
      }
   }
</script>
<style lang="scss">
   .text-cover {
      display: flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
      color: #fff;
      font-size: 28rpx;
      padding: 16rpx;
      line-height: 1.4;
   }
   /* 视频列表专用样式 */
   .video-item {
      display: flex;
      padding: 24rpx 0;
      border-bottom: 1rpx solid #f5f5f5;
      align-items: center;
      &:last-child {
         border-bottom: none;
      }
   }
   .video-cover-container {
      position: relative;
      width: 240rpx;
      height: 160rpx;
      border-radius: 12rpx;
      overflow: hidden;
      margin-right: 24rpx;
      flex-shrink: 0;
      .video-cover {
         width: 100%;
         height: 100%;
      }
      .play-icon {
         position: absolute;
         top: 50%;
         left: 50%;
         transform: translate(-50%, -50%);
         opacity: 0.9;
      }
      .video-duration {
         position: absolute;
         right: 8rpx;
         bottom: 8rpx;
         background: rgba(0, 0, 0, 0.6);
         color: #fff;
         font-size: 20rpx;
         padding: 4rpx 12rpx;
         border-radius: 20rpx;
      }
   }
   .video-info {
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      height: 160rpx;
      .video-title {
         font-size: 30rpx;
         color: #333;
         font-weight: bold;
         display: -webkit-box;
         -webkit-box-orient: vertical;
         -webkit-line-clamp: 2;
         overflow: hidden;
      }
      .video-meta {
         display: flex;
         justify-content: space-between;
         font-size: 24rpx;
         color: #999;
         .video-weight {
            display: flex;
            align-items: center;
         }
      }
   }
   .video-actions {
      margin-left: 20rpx;
      flex-shrink: 0;
      .cancel-btn {
         background: #f5f5f5;
         color: #666;
         border: none;
         font-size: 24rpx;
         padding: 8rpx 20rpx;
         border-radius: 20rpx;
         &:active {
            background: #eee;
         }
      }
   }
   .empty-tip {
      text-align: center;
      padding: 100rpx 0;
      image {
         width: 300rpx;
         margin-bottom: 30rpx;
         opacity: 0.6;
      }
      text {
         display: block;
         font-size: 28rpx;
         color: #999;
      }
   }
   .activity-container {
      padding: 20rpx;
      background-color: #f5f5f5;