绿满眶商城微信小程序-uniapp
peng
4 天以前 5027240f2bbc9a7f74b8cc661c265eb9d52eb43a
pages/video/home-page.vue
@@ -4,14 +4,11 @@
    <view class="user-header">
      <view class="user-avatar-container">
        <image class="user-avatar" :src="userInfo.avatar" mode="aspectFill"></image>
        <view class="edit-icon" @click="editProfile" v-if="isSelf">
          <uni-icons type="compose" size="20" color="#666"></uni-icons>
        </view>
      </view>
      <view class="user-info">
        <view class="user-name">{{userInfo.nickName}}</view>
        <view class="user-id">ID: {{userInfo.userId}}</view>
        <view class="user-desc">{{userInfo.motto || '这个人很懒,什么都没留下~'}}</view>
        <view class="user-desc">{{userInfo.motto || '没有签名,也很个性~'}}</view>
      </view>
      <view class="stats-container">
        <view class="stat-item" @click="navigateToFollow('fans')">
@@ -38,6 +35,10 @@
          {{userInfo.hasSub ? '取消关注' : '关注'}}
        </button>
      </view>
     <view class="edit-icon" @click="editInfo" v-if="userInfo.self">
       <uni-icons type="compose" size="20" color="#666"></uni-icons>编辑主页信息
     </view>
    </view>
    
        <!-- 作品/喜欢切换 -->
@@ -47,7 +48,7 @@
            :class="{active: currentTab === 'works'}" 
            @click="switchTab('works')"
          >
            作品
            作品{{`(${videoTotal})`}}
          </view>
          <view 
            class="tab-item" 
@@ -59,38 +60,98 @@
        </view>
        
        <!-- 视频列表 -->
        <view class="video-list">
          <view
            class="video-item"
            v-for="(item, index) in videoList"
            :key="item.id"
            @click="playVideo(index)"
          >
            <image class="video-cover" :src="item.cover" mode="aspectFill"></image>
            <view class="video-info">
              <view class="video-stats">
                <view class="stat">
                  <uni-icons type="heart" size="14" color="#fff"></uni-icons>
                  <text>{{item.collectNum}}</text>
                </view>
              </view>
            </view>
          </view>
        </view>
      <scroll-view class="video-list" scroll-y :show-scrollbar="false" @scrolltolower="getPage" v-show="currentTab === 'works' && videoList.length > 0">
         <view class="video-container">
            <view
              class="video-item"
              v-for="(item, index) in videoList"
              :key="item.id"
            >
              <image class="video-cover" @click="playAuthorVideo(index)" :src="item.videoContentType === 'video' ? item.coverUrl : item.imgs[0]" mode="aspectFill"></image>
              <view class="video-info">
                <view class="video-stats">
                  <view class="stat">
                    <uni-icons type="heart" size="16" color="#fff"></uni-icons>
                    <text>{{item.collectNum}}</text>
                  <view class="more-op" v-if="userInfo.self">
                     <dropdown-menu
                     :options="item.options"
                     :data="{id: item.id, title: item.title}"
                     placement="top"
                     theme-color="#07C160"
                     @change="handleChange"
                     ></dropdown-menu>
                  </view>
                  </view>
                </view>
              </view>
            </view>
         </view>
      </scroll-view>
      <scroll-view class="video-list" scroll-y :show-scrollbar="false" @scrolltolower="getPage" v-show="currentTab === 'likes' && collectVideoList.length > 0">
         <view class="video-container">
            <view
              class="video-item"
              v-for="(item, index) in collectVideoList"
              :key="item.id"
              @click="playCollectVideo(index)"
            >
              <image class="video-cover" :src="item.videoContentType === 'video' ? item.coverUrl : item.imgs[0]" mode="aspectFill"></image>
              <view class="video-info">
                <view class="video-stats">
                  <view class="stat">
                    <uni-icons type="heart" size="16" color="#fff"></uni-icons>
                    <text>{{item.collectNum}}</text>
                  </view>
                </view>
              </view>
            </view>
         </view>
      </scroll-view>
        
        <!-- 空状态 -->
        <view class="empty-state" v-if="videoList.length === 0">
          <image src="/static/images/empty.png" mode="aspectFit" class="empty-image"></image>
          <text class="empty-text">{{currentTab === 'works' ? '你还没有发布作品哦~' : '你还没有点赞作品哦~'}}</text>
        <view class="empty-state" v-if="videoList.length === 0 && currentTab === 'works'">
          <!-- <image src="/static/images/empty.png" mode="aspectFit" class="empty-image"></image> -->
          <text class="empty-text">还未发布作品哦~</text>
        </view>
      <!-- 空状态 -->
      <view class="empty-state" v-if="collectVideoList.length === 0 && currentTab === 'likes'">
        <!-- <image src="/static/images/empty.png" mode="aspectFit" class="empty-image"></image> -->
        <text class="empty-text">还没有点赞作品哦~</text>
      </view>
      <!-- 删除视频提醒框 -->
      <uni-popup ref="delDialog" type="dialog">
         <uni-popup-dialog type="error" cancelText="取消" confirmText="删除" title="提醒" :content="`您正在删除:${opVideo.title}`" @confirm="deleteVideo"
            @close="dialogClose"></uni-popup-dialog>
      </uni-popup>
      <!-- 下架视频提醒框 -->
      <uni-popup ref="downDialog" type="dialog">
         <uni-popup-dialog type="error" cancelText="取消" confirmText="下架" title="提醒" :content="`您正在下架:${opVideo.title}`" @confirm="downVideo"
            @close="dialogClose"></uni-popup-dialog>
      </uni-popup>
  </view>
</template>
<script>
import {getAuthorInfo, getAuthorVideoPage} from '@/api/user.js'
import DropdownMenu from '@/components/dropdown-menu.vue'
import {getAuthorInfo, getAuthorVideoPage, getAuthorCollectVideoPage} from '@/api/user.js'
import {subscribe, unSubscribe, delVideo, updateVideo, userDownVideo} from '@/api/video.js'
export default {
  components: {DropdownMenu},
  data() {
    return {
     options: [
         { command: 1, label: '北京' },
         { command: 2, label: '上海' },
         { command: 3, label: '广州' }
        ],
     opVideo: { // 正在操作的视频
        id: '',
        title: ''
     },
      currentTab: 'works', // works: 作品, likes: 喜欢
      authorId: '',
      userInfo: {
@@ -109,8 +170,20 @@
        pageNumber: 1,
        pageSize: 10
     },
      videoList: []
     collectVideoQuery: {
        authorId: '',
        pageNumber: 1,
        pageSize: 10
     },
     videoTotal: 0,
      videoList: [], // 作品
     collectVideoList: [], // 收藏
     nomoreVideo: false,
     nomoreCollectVideo: false
    }
  },
  onShow() {
    this.getAuthorInfo();
  },
  onLoad(option) {
   this.authorId = option.authorId;
@@ -118,75 +191,196 @@
   this.getAuthorVideoPage();
  },
  methods: {
   dialogClose() {
      this.opVideo = {
         id: '',
         title: ''
      }
   },
   // 下架视频
   downVideo() {
      userDownVideo(this.opVideo.id).then(res => {
         uni.showToast({
            title: '下架成功',
            duration: 2000
         });
         // 刷新数据
         this.videoList = [];
         this.videoQuery.pageNumber = 1;
         this.getAuthorVideoPage();
      })
   },
   // 删除视频
   deleteVideo() {
      delVideo(this.opVideo.id).then(res => {
         uni.showToast({
            title: '删除成功',
            duration: 2000
         });
         // 刷新数据
         this.videoList = [];
         this.videoQuery.pageNumber = 1;
         this.getAuthorVideoPage();
      })
   },
   // 触发视频操作
   handleChange(value, data) {
       console.log('选中值:', value)
      this.opVideo.id = data.id;
      this.opVideo.title = data.title;
      if (value === 'DELETE') {
         this.$refs.delDialog.open()
      } else if (value === 'DOWN') {
         this.$refs.downDialog.open()
      } else if (value === 'EDIT') {
         // 跳转编辑视频页面
         uni.navigateTo({
           url: `/pages/video/video-edit?id=${this.opVideo.id}`
         });
      }
   },
   getPage() {
      if(this.currentTab === 'works') {
         if(this.nomoreVideo) {
            return;
         }
         getAuthorVideoPage(this.videoQuery).then(res => {
            if(this.videoQuery.pageNumber === 1) {
               this.videoList = res.data.data
            } else {
               this.videoList = [
                 ...this.videoList,
                 ...res.data.data.filter(
                   (newItem) => !this.videoList.some((oldItem) => oldItem.id === newItem.id)
                 ),
               ];
            }
            if(res.data.data.length < this.videoQuery.pageSize) {
               this.nomoreVideo = true;
            } else {
               this.videoQuery.pageNumber += 1;
            }
         })
      } else if(this.currentTab === 'likes') {
         if(this.nomoreCollectVideo) {
            return;
         }
         getAuthorCollectVideoPage(this.collectVideoQuery).then(res => {
            if(this.collectVideoQuery.pageNumber === 1) {
               this.collectVideoList = res.data.data
            } else {
               this.collectVideoList = [
                 ...this.collectVideoList,
                 ...res.data.data.filter(
                   (newItem) => !this.collectVideoList.some((oldItem) => oldItem.id === newItem.id)
                 ),
               ];
            }
            if(res.data.data.length < this.collectVideoQuery.pageSize) {
               this.nomoreCollectVideo = true;
            } else {
               this.collectVideoQuery.pageNumber += 1;
            }
         })
      }
   },
   // 获取个人信息
   async getAuthorInfo() {
      getAuthorInfo(this.authorId).then(res => {
         this.userInfo = res.data.data
      })
   },
   // 获取作者作品
   async getAuthorVideoPage() {
      this.videoQuery.authorId = this.authorId;
      getAuthorVideoPage(this.videoQuery).then(res => {
         if(this.videoQuery.pageNumber === 1) {
            this.videoList = res.data.data
         } else {
            this.videoList = [
              ...this.videoList,
              ...res.data.data.filter(
                (newItem) => !this.videoList.some((oldItem) => oldItem.id === newItem.id)
              ),
            ];
         this.videoList = res.data.data
         this.videoTotal = res.data.total
         if(res.data.data.length < this.videoQuery.pageSize) {
            this.nomoreVideo = true;
         }
      })
   },
   // 获取作品信息
    // 切换关注状态
    toggleFollow() {
      // 模拟请求服务器
      uni.showLoading({
        title: '处理中...'
      });
      setTimeout(() => {
        this.isFollowed = !this.isFollowed;
        // 更新粉丝数
        if(this.isFollowed) {
          this.userInfo.fansCount++;
          uni.showToast({
            title: '关注成功',
            icon: 'success'
          });
        } else {
          this.userInfo.fansCount--;
          uni.showToast({
            title: '已取消关注',
            icon: 'none'
          });
        }
        uni.hideLoading();
      }, 500);
      if(this.userInfo.hasSub) {
        // 取消关注
        unSubscribe(this.authorId).then(res => {
           uni.showToast({
             title: '已取消关注',
             icon: 'none'
           });
           this.userInfo.hasSub = false
           this.userInfo.fansNum -= 1;
        })
     } else {
        // 关注
        subscribe(this.authorId).then(res => {
           uni.showToast({
             title: '关注成功',
             icon: 'success'
           });
           this.userInfo.hasSub = true
           this.userInfo.fansNum += 1;
        })
     }
    },
   // 切换作品/喜欢tab
    switchTab(tab) {
     if(this.currentTab === tab) {
        return
     }
      this.currentTab = tab;
      // 这里应该根据tab切换请求不同的数据
      // this.loadVideoList();
     if(tab === 'works') {
        this.collectVideoList = []
        this.videoQuery.pageNumber = 1
        this.getAuthorVideoPage()
     } else if(tab === 'likes') {
        this.videoList = []
        this.collectVideoQuery.pageNumber = 1
        this.getAuthorCollectVideoPage()
     }
    },
    // 播放视频
    playVideo(index) {
      const videoItem = this.videoList[index];
   // 获取作者的收藏视频
    async getAuthorCollectVideoPage() {
      this.collectVideoQuery.authorId = this.authorId
      getAuthorCollectVideoPage(this.collectVideoQuery).then(res => {
         this.collectVideoList = res.data.data
         if(res.data.data.length < this.collectVideoQuery.pageSize) {
            this.nomoreCollectVideo = true;
         }
      })
   },
    // 播放作者视频
    playAuthorVideo(index) {
     const playInfo = {
        videoList: this.videoList,
        nomore: this.nomoreVideo,
        pageNumber: this.videoQuery.pageNumber,
        playIndex: index
     }
     uni.setStorageSync("playInfo", playInfo)
      uni.navigateTo({
        url: `/pages/video/play?id=${videoItem.id}`
        url: `/pages/video/video-play?authorId=${this.authorId}&videoFrom=author`
      });
    },
    // 编辑个人资料
    editProfile() {
    // 播放收藏视频
    playCollectVideo(index) {
      const playInfo = {
         videoList: this.collectVideoList,
         nomore: this.nomoreCollectVideo,
         pageNumber: this.collectVideoQuery.pageNumber,
         playIndex: index
      }
      uni.setStorageSync("playInfo", playInfo)
      uni.navigateTo({
        url: '/pages/user/edit'
        url: `/pages/video/video-play?authorId=${this.authorId}&videoFrom=collect`
      });
    },
    // 编辑个人资料
    editInfo() {
      uni.navigateTo({
        url: `/pages/video/home-page-edit?authorId=${this.authorId}&avatar=${this.userInfo.avatar}&motto=${this.userInfo.motto || ''}&nickName=${this.userInfo.nickName}`
      });
    },
    
@@ -208,9 +402,12 @@
</script>
<style lang="scss" scoped>
body {
   background-color: #fff !important;
}
.container {
  padding-bottom: 20rpx;
  background-color: #f5f5f5;
  background-color: white;
  min-height: 100vh;
}
@@ -238,16 +435,13 @@
.edit-icon {
  position: absolute;
  right: 0;
  bottom: 0;
  right: 30rpx;
  top: 30rpx;
  background-color: #fff;
  border-radius: 50%;
  width: 40rpx;
  height: 40rpx;
  display: flex;
  justify-content: center;
  align-items: center;
  box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
}
.user-info {
@@ -300,7 +494,7 @@
.tab-bar {
  display: flex;
  background-color: #fff;
  margin-bottom: 20rpx;
  padding-bottom: 20rpx;
}
.tab-item {
@@ -330,32 +524,38 @@
}
.video-list {
  width: 100%;
    padding: 0 10rpx;
    height: calc(100vh - 554rpx);
    background-color: #fff;
}
.video-container {
  display: flex;
  flex-wrap: wrap;
  padding: 0 10rpx;
  justify-content: space-between;
}
.video-item {
  width: 50%;
  padding: 10rpx;
  box-sizing: border-box;
  width: 49%;
  margin-bottom: 20rpx;
  position: relative;
}
.video-cover {
  width: 100%;
  height: 350rpx;
  height: 500rpx;
  border-radius: 10rpx;
  display: block;
}
.video-info {
  position: absolute;
  bottom: 20rpx;
  left: 20rpx;
  right: 20rpx;
  color: #fff;
  font-size: 24rpx;
  bottom: 10rpx;
  left: 0;
  right: 0;
  padding: 0 10rpx;
  box-sizing: border-box;
}
.video-title {
@@ -369,17 +569,25 @@
.video-stats {
  display: flex;
  width: 100%;
}
.stat {
  display: flex;
  width: 100%;
  align-items: center;
  margin-right: 20rpx;
  text-shadow: 0 0 5rpx rgba(0, 0, 0, 0.5);
  position: relative;
}
.more-op {
   position: absolute;
   right: 0;
}
.stat text {
  margin-left: 5rpx;
  color: #fff;
  font-size: 14px;
}
.empty-state {
@@ -427,8 +635,4 @@
  }
}
/* 如果是自己的主页,隐藏关注按钮 */
.user-header {
  position: relative;
}
</style>