绿满眶商城微信小程序-uniapp
zxl
2025-07-29 9ac342cdebca34f39243d4d724709f55dc02baac
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,355 +8,389 @@
         </view>
      </view>
      <!-- 视频列表 -->
      <view class="activity-list">
         <view v-if="currentTab === 0">
            <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="item.id" class="video-item">
                     <!-- 视频封面+播放按钮 -->
                     <view class="video-cover-container" @click="jumpToPlay(idx)">
                        <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="video-info" @click="jumpToPlay(idx)">
                        <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',idx)">
                           取消收藏
                        </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">
            <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="item.id" class="activity-item">
                     <!-- 封面区域 -->
                     <block>
                        <image :src="item.original" mode="aspectFill" class="activity-cover" />
                     </block>
                     <!-- 活动信息 -->
                     <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 class="action-container">
                        <button class="cancel-btn" @click="handleCancelCollection(item,'goods',idx)"
                           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="goodsCollects.length > 0"
                     :status="loading ? 'loading' : noMore ? 'nomore' : 'loadmore'" :load-text="{
                  loadmore: '上拉加载更多',
                  loading: '正在加载',
                  nomore: '没有更多了'
                }" />
               </view>
            </scroll-view>
         </view>
         <view v-if="currentTab === 2">
            <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="item.id" 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', idx)"
                           hover-class="cancel-btn-hover">
                           取消收藏
                        </button>
                     </view>
      <!-- 视频收藏列表 -->
      <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="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.stop="handleCancelCollection(item, 'video', idx)"
                        hover-class="cancel-btn-hover">
                        取消收藏
                     </button>
                  </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>
            </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="videoCollects.length > 0" :status="loadStatus" :load-text="{
              loadmore: '上拉加载更多',
              loading: '正在加载',
              nomore: '没有更多了'
            }" />
            </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.original" 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 '@/components/uview-components/uview-ui';
   import storage from '@/utils/storage';
   import {getAuthorCollectVideoPage} from '@/api/user.js'
   import {
      getFilePreviewUrl
   } from '@/api/common.js'
   import {
      changeCollect,
      getMyCollectList
      getMyCollectList,
      changeCollect
   } from '@/api/collect.js'
   import {
      ifError
   } from 'assert'
   export default {
   import storage from '@/utils/storage'
   export default {
      data() {
         return {
            total: 0,
            loading: false,
            noMore: false,
            currentTab: 0, // 当前选中的tab索引
            currentTab: 0,
            tabs: ['视频', '商品', '活动'],
            //
            videoCollects: [], // 收藏视频列表
            goodsCollects: [], // 收藏商品列表
            activityCollects: [], // 收藏活动列表
            collectForm: {
               collectType: '',
               refId: '',
            },
            videoCollects: [],
            goodsCollects: [],
            activityCollects: [],
            query: {
               authorId: '',
               type: 'video',
               pageNumber: 1,
               pageSize: 5,
            }
               pageSize: 5
            },
            loading: false,
            noMore: false,
            total: 0
         }
      },
      computed: {
         loadStatus() {
            return this.loading ? 'loading' : this.noMore ? 'nomore' : 'loadmore'
         }
      },
      onLoad() {
         this.currentTab = 0;
         this.query.authorId = storage.getUserInfo().id
         this.getintit()
         this.loadData()
      },
      onPullDownRefresh() {
         this.query.pageNumber = 1
         this.noMore = false
         this.videoCollects = []
         this.goodsCollects = []
         this.activityCollects = []
         this.loadData().finally(() => {
            uni.stopPullDownRefresh()
         })
      },
      methods: {
         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`
            });
         async getVideoCover(videoPath) {
            return null;
         },
         /**
          * 下拉刷新时
          */
         onPullDownRefresh() {
            this.currentTab = 0;
            this.query.pageNumber = 1; // 重置页码
            this.noMore = false;
            this.videoCollects = [];
            this.goodsCollects = []; // 收藏商品列表
            this.activityCollects = []; // 收藏活动列表// 清空数据
            this.getintit();
         },
         loadMore() {
            this.loading = true;
            // 延迟执行让UI有反应时间
            setTimeout(() => {
               this.query.pageNumber += 1;
               this.getintit();
            }, 300);
         },
         // 跳转到视频播放页
         // 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) {
            console.log(item)
            this.collectForm.collectType = type;
            this.collectForm.refId = item.id;
            changeCollect(this.collectForm).then(res => {
               if (res.data.code === 200) {
                  uni.showToast({
                     title: res.data.msg, // 提示文字
                     icon: 'none', // 图标类型(success/loading/none)
                     mask: true // 是否显示透明蒙层(防止触摸穿透)
                  });
                  this.query.pageNumber = 1
                  // 因为视频走的mq有延迟,前端直接删除该元素达到效果
                  if (type === 'video') {
                     this.videoCollects.splice(index, 1)
                  } else {
                     this.noMore = false
                     this.getintit()
            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()
                           }
                        }
                     })
                  }
               }
            })
         },
            })
         },
         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 = [];
               // 实际项目中可以在这里添加加载数据的逻辑
               this.getintit()
               this.query.pageNumber = 1
               this.query.type = ['video', 'goods', 'activity'][index]
               this.videoCollects = []
               this.goodsCollects = []
               this.activityCollects = []
               this.loadData()
            }
         },
         async getintit() {
         // 加载更多
         loadMore() {
            if (!this.loading && !this.noMore) {
               this.query.pageNumber += 1
               this.loadData()
            }
         },
         // 加载数据
         async loadData() {
            if (this.loading) return
            this.loading = true
            uni.showLoading({
               title: '加载中'
            });
            if (this.currentTab === 0) {
               this.query.type = 'video';
               getAuthorCollectVideoPage(this.query).then(res => {
                  uni.hideLoading();
                  this.loading = false;
            })
                  if (res.data.code === 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';
            try {
               getMyCollectList(this.query).then(res => {
                  uni.hideLoading();
                  this.loading = false;
                  if (res.data.code === 200) {
                     const newData = res.data.data
                     this.total = res.data.total || 0;
                     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.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.activityCollects = this.query.pageNumber === 1 ?
                        newData :
                        [...this.activityCollects, ...newData];
                     this.noMore = newData.length < this.query.pageSize ||
                        this.activityCollects.length >= this.total;
                        (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">
   .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;
   .page-container {
      padding: 20rpx;
      background-color: #f5f5f5;
      min-height: 100vh;
   }
   /* 视频列表专用样式 */
   .video-item {
   .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;
         &.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;
            }
         }
      }
   }
   .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);
      }
   }
   .collect-item {
      display: flex;
      padding: 24rpx 0;
      border-bottom: 1rpx solid #f5f5f5;
@@ -368,18 +401,31 @@
      }
   }
   .video-cover-container {
   .cover-container {
      position: relative;
      width: 240rpx;
      height: 160rpx;
      width: 250rpx;
      height: 180rpx;
      border-radius: 12rpx;
      overflow: hidden;
      margin-right: 24rpx;
      flex-shrink: 0;
      .video-cover {
      .cover-image {
         width: 100%;
         height: 100%;
      }
      .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 {
@@ -390,7 +436,7 @@
         opacity: 0.9;
      }
      .video-duration {
      .duration {
         position: absolute;
         right: 8rpx;
         bottom: 8rpx;
@@ -402,14 +448,14 @@
      }
   }
   .video-info {
   .info-container {
      flex: 1;
      height: 160rpx;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      height: 160rpx;
      .video-title {
      .title {
         font-size: 30rpx;
         color: #333;
         font-weight: bold;
@@ -419,22 +465,21 @@
         overflow: hidden;
      }
      .video-meta {
      .meta {
         display: flex;
         justify-content: space-between;
         font-size: 24rpx;
         color: #999;
         flex-wrap: wrap;
         .video-weight {
         .meta-item {
            display: flex;
            align-items: center;
            margin-right: 20rpx;
            font-size: 24rpx;
            color: #999;
         }
      }
   }
   .video-actions {
   .action-container {
      margin-left: 20rpx;
      flex-shrink: 0;
@@ -458,6 +503,7 @@
      image {
         width: 300rpx;
         height: 300rpx;
         margin-bottom: 30rpx;
         opacity: 0.6;
      }
@@ -469,138 +515,7 @@
      }
   }
   .activity-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;
      &.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;
         }
      }
   }
   /* 活动列表样式 */
   .activity-list {
      background-color: #fff;
      border-radius: 12rpx;
      padding: 20rpx;
      box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
   }
   .activity-item {
      display: flex;
   .load-more {
      padding: 20rpx 0;
      border-bottom: 1rpx solid #eee;
      &:last-child {
         border-bottom: none;
      }
   }
   .activity-cover {
      width: 200rpx;
      height: 140rpx;
      border-radius: 8rpx;
      margin-right: 20rpx;
   }
   .activity-info {
      flex: 1;
      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;
      overflow: hidden;
   }
   .activity-meta {
      font-size: 24rpx;
      color: #999;
      margin-bottom: 16rpx;
      text {
         display: block;
         margin-bottom: 8rpx;
      }
   }
   .activity-status {
      position: absolute;
      right: 0;
      top: 0;
      font-size: 24rpx;
      padding: 4rpx 12rpx;
      border-radius: 20rpx;
      &.signed {
         color: #007AFF;
         background-color: rgba(0, 122, 255, 0.1);
      }
      &.ended {
         color: #999;
         background-color: rgba(153, 153, 153, 0.1);
      }
      &.canceled {
         color: #ff3b30;
         background-color: rgba(255, 59, 48, 0.1);
      }
   }
   /* 空状态提示 */
   .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;
      }
   }
</style>