绿满眶商城微信小程序-uniapp
peng
2025-08-08 8a2d6949a4525f90e0e75f2f3f83c13b8830a758
pages/mine/myCollect/myCollect.vue
@@ -1,6 +1,5 @@
<template>
   <view class="activity-container">
   <view class="page-container">
      <!-- 顶部 Tab 导航 -->
      <view class="tab-nav">
         <view v-for="(tab, index) in tabs" :key="index" class="tab-item" :class="{active: currentTab === index}"
@@ -9,323 +8,502 @@
         </view>
      </view>
      <!-- 视频列表 -->
      <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>
      <!-- 视频收藏列表 -->
      <view v-if="currentTab === 0" class="list-container">
         <scroll-view scroll-y class="scroll-view" @scrolltolower="loadMore" :lower-threshold="100">
            <view v-if="videoCollects.length > 0">
               <view v-for="(item, idx) in videoCollects" :key="item.id" class="collect-item">
                  <!-- 视频封面 -->
                  <image v-if="tem.videoContentType === 'img'" class="cover-image" :src="item.imgs[0]" mode="aspectFill"></image>
                  <view v-else class="cover-container">
                     <video class="cover-image"
                     :src="item.videoUrl"
                     initial-time='0.01'
                     muted
                     :controls="false"
                     :show-center-play-btn="false"
                     object-fit="cover"></video>
                     <!--  <image :src="getVideoCover()" mode="aspectFill" class="cover-image" /> -->
                     <!--   <view v-if="item.duration" class="duration">
                {{ formatDuration(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="info-container">
                     <view class="title">{{ item.title || '无标题视频' }}</view>
                     <view class="meta">
                        <view class="meta-item">
                           <u-icon name="account-fill" size="24" color="#999"></u-icon>
                           {{ item.authorName || '未知作者' }}
                        </view>
                        <view class="meta-item" v-if="item.weight > 0">
                           <u-icon name="thumb-up-fill" size="24" color="#999"></u-icon>
                           {{ item.weight }}
                        </view>
                     </view>
                  </view>
                  <!-- 操作区域 -->
                  <!-- 取消收藏按钮 -->
                  <view class="action-container">
                     <button class="cancel-btn" @click="handleCancelCollection(item)"
                     <button class="cancel-btn" @click.stop="handleCancelCollection(item, 'video', idx)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </view>
               </view>
            </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>
                  <!-- 活动信息 -->
                  <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>
                  </view>
                  <!-- 操作区域 -->
                  <view class="action-container">
                     <button class="cancel-btn" @click="handleCancelCollection(item)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </view>
               </view>
            <view v-else class="empty-tip">
               <image src="/static/empty.png" mode="aspectFit" />
               <text>暂无收藏视频</text>
            </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>
                     </view>
                  </view>
                  <!-- 操作区域 -->
                  <view class="action-container">
                     <button class="cancel-btn" @click="handleCancelCollection(item)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </view>
               </view>
            <view class="load-more">
               <u-loadmore v-if="videoCollects.length > 0" :status="loadStatus" :load-text="{
              loadmore: '上拉加载更多',
              loading: '正在加载',
              nomore: '没有更多了'
            }" />
            </view>
         </view>
         </scroll-view>
      </view>
      <!-- 商品收藏列表 -->
      <view v-if="currentTab === 1" class="list-container">
         <scroll-view scroll-y class="scroll-view" @scrolltolower="loadMore" :lower-threshold="100">
            <view v-if="goodsCollects.length > 0">
               <view v-for="(item, idx) in goodsCollects" :key="item.id" class="collect-item">
                  <!-- 商品封面 -->
                  <view class="cover-container">
                     <image :src="item.image" mode="aspectFill" class="cover-image" />
                  </view>
                  <!-- 商品信息 -->
                  <view class="info-container">
                     <view class="title">{{ item.goodsName }}</view>
                     <view class="meta">
                        <view class="meta-item">
                           <u-icon name="rmb-circle-fill" size="24" color="#FF5500"></u-icon>
                           {{ item.price }}元
                        </view>
                     <!--    <view class="meta-item">
                           <u-icon name="home-fill" size="24" color="#999"></u-icon>
                           {{ item.storeName || '暂无' }}
                        </view> -->
                     </view>
                  </view>
                  <!-- 取消收藏按钮 -->
                  <view class="action-container">
                     <button class="cancel-btn" @click.stop="handleCancelCollection(item, 'goods', idx)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </view>
               </view>
            </view>
            <view v-else class="empty-tip">
               <image src="/static/empty.png" mode="aspectFit" />
               <text>暂无收藏商品</text>
            </view>
            <view class="load-more">
               <u-loadmore v-if="goodsCollects.length > 0" :status="loadStatus" :load-text="{
              loadmore: '上拉加载更多',
              loading: '正在加载',
              nomore: '没有更多了'
            }" />
            </view>
         </scroll-view>
      </view>
      <!-- 活动收藏列表 -->
      <view v-if="currentTab === 2" class="list-container">
         <scroll-view scroll-y class="scroll-view" @scrolltolower="loadMore" :lower-threshold="100">
            <view v-if="activityCollects.length > 0">
               <view v-for="(item, idx) in activityCollects" :key="item.id" class="collect-item">
                  <!-- 活动封面 -->
                  <view class="cover-container">
                     <image v-if="item.coverType === '图片' || item.coverType === '视频'" :src="item.cover"
                        mode="aspectFill" class="cover-image" />
                     <view v-else-if="item.coverType === '文字'" class="text-cover">
                        {{ item.cover }}
                     </view>
                  </view>
                  <!-- 活动信息 -->
                  <view class="info-container">
                     <view class="title">{{ item.activityName }}</view>
                     <view class="meta">
                        <view class="meta-item">
                           <u-icon name="calendar-fill" size="24" color="#999"></u-icon>
                           {{ item.startTime }} ~ {{ item.endTime }}
                        </view>
                        <view class="meta-item">
                           <u-icon name="map-pin-fill" size="24" color="#999"></u-icon>
                           {{ item.activityLocation || '暂无' }}
                        </view>
                     </view>
                  </view>
                  <!-- 取消收藏按钮 -->
                  <view class="action-container">
                     <button class="cancel-btn" @click.stop="handleCancelCollection(item, 'activity', idx)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </view>
               </view>
            </view>
            <view v-else class="empty-tip">
               <image src="/static/empty.png" mode="aspectFit" />
               <text>暂无收藏活动</text>
            </view>
            <view class="load-more">
               <u-loadmore v-if="activityCollects.length > 0" :status="loadStatus" :load-text="{
              loadmore: '上拉加载更多',
              loading: '正在加载',
              nomore: '没有更多了'
            }" />
            </view>
         </scroll-view>
      </view>
   </view>
</template>
<script>
   import {
      getMyActivityList,
      activityCancel
   } from '@/api/activity.js'
   import {
      getPreviewUrl
   } from '@/api/common.js'
      getMyCollectList,
      changeCollect
   } from '@/api/collect.js'
   import storage from '@/utils/storage'
   export default {
      data() {
         return {
            currentTab: 0, // 当前选中的tab索引
            currentTab: 0,
            tabs: ['视频', '商品', '活动'],
            //
            videoCollects: [], // 收藏视频列表
            storeCollects: [], // 收藏商品列表
            activityCollects: [], // 收藏活动列表
            videoCollects: [],
            goodsCollects: [],
            activityCollects: [],
            query: {
               id: '',
               status: '',
               cancel: false,
               authorId: '',
               type: 'video',
               pageNumber: 1,
               pageSize: 5
            },
            loading: false,
            noMore: false,
            total: 0
         }
      },
      onLoad(){
         this.currentTab = 0;
         //TODO 未登录需要id,测试用写死\
         this.switchTab(this.currentTab);
      computed: {
         loadStatus() {
            return this.loading ? 'loading' : this.noMore ? 'nomore' : 'loadmore'
         }
      },
      onLoad() {
         this.query.authorId = storage.getUserInfo().id
         this.loadData()
      },
      onPullDownRefresh() {
         this.query.pageNumber = 1
         this.noMore = false
         this.videoCollects = []
         this.goodsCollects = []
         this.activityCollects = []
         this.loadData().finally(() => {
            uni.stopPullDownRefresh()
         })
      },
      methods: {
         handleCancelCollection(id) {
         async getVideoCover(videoPath) {
            return null;
         },
         // 跳转到视频播放页
         // jumpToPlay(index) {
         //   const playInfo = {
         //     videoList: this.videoCollects,
         //     nomore: this.noMore,
         //     pageNumber: this.query.pageNumber,
         //     playIndex: index
         //   }
         //   uni.setStorageSync("playInfo", playInfo)
         //   uni.navigateTo({
         //     url: `/pages/video/video-play?authorId=${this.query.authorId}&videoFrom=collect`
         //   })
         // },
         // 取消收藏
         handleCancelCollection(item, type, index) {
            uni.showModal({
               title: '提示',
               content: '确定要取消收藏吗?',
               success: (res) => {
                  if (res.confirm) {
                     changeCollect({
                        collectType: type,
                        refId: item.id
                     }).then(res => {
                        if (res.data.code === 200) {
                           uni.showToast({
                              title: res.data.msg,
                              icon: 'none'
                           })
                           if (type === 'video') {
                              this.videoCollects.splice(index, 1)
                           } else {
                              this.query.pageNumber = 1
                              this.noMore = false
                              this.loadData()
                           }
                        }
                     })
                  }
               }
            })
         },
         getPreviewUrl(params) {
            // return getPreviewUrl(params);
            return '';
         },
         // 切换tab
         // 切换标签页
         switchTab(index) {
            if (this.currentTab !== index) {
               this.currentTab = index
               // 实际项目中可以在这里添加加载数据的逻辑
               if (this.currentTab === 0) {
                  //加载视频列表
                  this.getMyCollectionVideoList();
               } else if (this.currentTab === 1) {
                  //加载商品列表
                  this.getMyCollectionStoreList();
               } else if (this.currentTab === 2) {
                  //加载活动列表
                  this.getMyCollectActivityList();
               }
               this.query.pageNumber = 1
               this.query.type = ['video', 'goods', 'activity'][index]
               this.videoCollects = []
               this.goodsCollects = []
               this.activityCollects = []
               this.loadData()
            }
         },
         // 加载更多
         loadMore() {
            if (!this.loading && !this.noMore) {
               this.query.pageNumber += 1
               this.loadData()
            }
         },
         getMyCollectionStoreList() {
         // 加载数据
         async loadData() {
            if (this.loading) return
            this.loading = true
            uni.showLoading({
               title: '加载中'
            });
            uni.hideLoading();
         },
         getMyCollectionVideoList() {
            uni.showLoading({
               title: '加载中'
            });
            uni.hideLoading();
         },
         getMyCollectActivityList() {
            uni.showLoading({
               title: '加载中'
            });
            uni.hideLoading();
         },
            })
            try {
               getMyCollectList(this.query).then(res => {
                  if (res.data.code === 200) {
                     const newData = res.data.data
                     this.total = res.data.total || 0
                     // 根据当前标签页更新对应数据
                     if (this.currentTab === 0) {
                        this.videoCollects = this.query.pageNumber === 1 ?
                           newData :
                           [...this.videoCollects, ...newData]
                     } else if (this.currentTab === 1) {
                        this.goodsCollects = this.query.pageNumber === 1 ?
                           newData :
                           [...this.goodsCollects, ...newData]
                     } else if (this.currentTab === 2) {
                        this.activityCollects = this.query.pageNumber === 1 ?
                           newData :
                           [...this.activityCollects, ...newData]
                     }
                     this.noMore = newData.length < this.query.pageSize ||
                        (this.currentTab === 0 ? this.videoCollects :
                           this.currentTab === 1 ? this.goodsCollects : this.activityCollects)
                        .length >= this.total
                  }
               });
            } catch (error) {
               console.error(error)
               uni.showToast({
                  title: '加载失败',
                  icon: 'none'
               })
            } finally {
               this.loading = false
               uni.hideLoading()
            }
         }
      }
   }
</script>
<style lang="scss">
   .activity-container {
   .page-container {
      padding: 20rpx;
      background-color: #f5f5f5;
      min-height: 100vh;
   }
   /* Tab 导航样式 */
   .tab-nav {
      display: flex;
      background-color: #fff;
      border-radius: 12rpx;
      margin-bottom: 20rpx;
      box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
   }
   .tab-item {
      flex: 1;
      text-align: center;
      padding: 24rpx 0;
      font-size: 28rpx;
      color: #666;
      position: relative;
      .tab-item {
         flex: 1;
         text-align: center;
         padding: 24rpx 0;
         font-size: 28rpx;
         color: #666;
         position: relative;
      &.active {
         color: #007AFF;
         font-weight: bold;
         &.active {
            color: #007AFF;
            font-weight: bold;
         &::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 80rpx;
            height: 6rpx;
            background-color: #007AFF;
            border-radius: 3rpx;
            &::after {
               content: '';
               position: absolute;
               bottom: 0;
               left: 50%;
               transform: translateX(-50%);
               width: 80rpx;
               height: 6rpx;
               background-color: #007AFF;
               border-radius: 3rpx;
            }
         }
      }
   }
   /* 活动列表样式 */
   .activity-list {
   .list-container {
      background-color: #fff;
      border-radius: 12rpx;
      padding: 20rpx;
      box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
      .scroll-view {
         height: calc(100vh - 200rpx);
      }
   }
   .activity-item {
   .collect-item {
      display: flex;
      padding: 20rpx 0;
      border-bottom: 1rpx solid #eee;
      padding: 24rpx 0;
      border-bottom: 1rpx solid #f5f5f5;
      align-items: center;
      &:last-child {
         border-bottom: none;
      }
   }
   .activity-cover {
      width: 200rpx;
      height: 140rpx;
      border-radius: 8rpx;
      margin-right: 20rpx;
   }
   .activity-info {
      flex: 1;
   .cover-container {
      position: relative;
   }
   .activity-title {
      font-size: 32rpx;
      color: #333;
      font-weight: bold;
      margin-bottom: 12rpx;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      width: 250rpx;
      height: 180rpx;
      border-radius: 12rpx;
      overflow: hidden;
   }
      margin-right: 24rpx;
      flex-shrink: 0;
   .activity-meta {
      font-size: 24rpx;
      color: #999;
      margin-bottom: 16rpx;
      .cover-image {
         width: 100%;
         height: 100%;
      }
      text {
         display: block;
         margin-bottom: 8rpx;
      .text-cover {
         width: 100%;
         height: 100%;
         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;
      }
      .play-icon {
         position: absolute;
         top: 50%;
         left: 50%;
         transform: translate(-50%, -50%);
         opacity: 0.9;
      }
      .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;
      }
   }
   .activity-status {
      position: absolute;
      right: 0;
      top: 0;
      font-size: 24rpx;
      padding: 4rpx 12rpx;
      border-radius: 20rpx;
   .info-container {
      flex: 1;
      height: 160rpx;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      &.signed {
         color: #007AFF;
         background-color: rgba(0, 122, 255, 0.1);
      .title {
         font-size: 30rpx;
         color: #333;
         font-weight: bold;
         display: -webkit-box;
         -webkit-box-orient: vertical;
         -webkit-line-clamp: 2;
         overflow: hidden;
      }
      &.ended {
         color: #999;
         background-color: rgba(153, 153, 153, 0.1);
      }
      .meta {
         display: flex;
         flex-wrap: wrap;
      &.canceled {
         color: #ff3b30;
         background-color: rgba(255, 59, 48, 0.1);
         .meta-item {
            display: flex;
            align-items: center;
            margin-right: 20rpx;
            font-size: 24rpx;
            color: #999;
         }
      }
   }
   /* 空状态提示 */
   .action-container {
      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;
         height: 300rpx;
         margin-bottom: 30rpx;
         opacity: 0.6;
      }
@@ -336,4 +514,8 @@
         color: #999;
      }
   }
   .load-more {
      padding: 20rpx 0;
   }
</style>