绿满眶商城微信小程序-uniapp
xiangpei
2025-06-03 12af499e64f38b7ff3a79fcc5bf527855cf359f3
视频主页基本信息接口对接
4个文件已修改
268 ■■■■ 已修改文件
api/user.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/video.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabbar/index/home.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/video/home-page.vue 232 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/user.js
@@ -33,3 +33,19 @@
    params: params
  });
}
/**
 * 获取视频主页-作者收藏的视频分页
 *
 * @param params
 */
 export function getAuthorCollectVideoPage(params) {
  return http.request({
    url: "/lmk/video/author-collect-video-page",
    method: Method.GET,
    needToken: true,
    params: params
  });
}
api/video.js
@@ -62,6 +62,19 @@
}
/**
 * 取消关注作者
 *
 * @param params
 */
 export function unSubscribe(authorId) {
  return http.request({
    url: "/lmk/my-subscribe/unSubscribe/" + authorId,
    method: Method.POST,
    needToken: true
  });
}
/**
 * 获取视频评论
 * 
 * @param params
pages/tabbar/index/home.vue
@@ -75,16 +75,16 @@
           <view class="avatar-container">
               <image class="avatar" @click="() => jumpToHomePage(item.authorId)" :src="item.authorAvatar" mode="aspectFill"></image>
               <!-- 关注图标 - 使用绝对定位 -->
               <view v-if="!item.subscribeThisAuthor" class="follow-icon" @click="subscribeAuth(index, item.authorId)">
               <view v-if="!item.subscribeThisAuthor" class="follow-icon" @click="() => subscribeAuth(index, item.authorId)">
                 <text class="iconfont">&#xe629;</text>
               </view>
           </view>
          <view class="action-item" @click="toggleCollect(item, index)">
          <view class="action-item" @click="() => toggleCollect(item, index)">
            <text class="iconfont" v-if="item.collected">&#xe605;</text>
            <text class="iconfont" v-else>&#xe601;</text>
            <text style="font-size: 10px;font-weight: lighter;">{{item.collectNum}}</text>
          </view>
         <view class="action-item" @click="showComments(item)">
         <view class="action-item" @click="() => showComments(item)">
            <text class="iconfont">&#xe7f7;</text>
            <text style="font-size: 10px;font-weight: lighter;">{{item.commentNum}}</text>
          </view>
@@ -495,7 +495,6 @@
    async loadVideos() {
      if (this.loading) return;
      this.loading = true;
      getRecommendVideos({pageNumber: this.page, pageSize: this.pageSize}).then(res => {
          console.log(res, "视频数据");
          if (this.page === 1) {
pages/video/home-page.vue
@@ -11,7 +11,7 @@
      <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')">
@@ -47,7 +47,7 @@
            :class="{active: currentTab === 'works'}" 
            @click="switchTab('works')"
          >
            作品
            作品{{`(${videoTotal})`}}
          </view>
          <view 
            class="tab-item" 
@@ -59,35 +59,63 @@
        </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"
                  @click="playVideo(index)"
                >
                  <image class="video-cover" :src="item.coverUrl" 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>
        <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="playVideo(index)"
                >
                  <image class="video-cover" :src="item.coverUrl" 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>
  </view>
</template>
<script>
import {getAuthorInfo, getAuthorVideoPage} from '@/api/user.js'
import {getAuthorInfo, getAuthorVideoPage, getAuthorCollectVideoPage} from '@/api/user.js'
import {subscribe, unSubscribe} from '@/api/video.js'
export default {
  data() {
    return {
@@ -109,7 +137,16 @@
          pageNumber: 1,
          pageSize: 10
      },
      videoList: []
      collectVideoQuery: {
          authorId: '',
          pageNumber: 1,
          pageSize: 10
      },
      videoTotal: 0,
      videoList: [], // 作品
      collectVideoList: [], // 收藏
      nomoreVideo: false,
      nomoreCollectVideo: false
    }
  },
  onLoad(option) {
@@ -118,63 +155,113 @@
    this.getAuthorVideoPage();
  },
  methods: {
    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
        })
    },
    // 获取作品信息
    // 切换关注状态
    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()
      }
    },
    // 获取作者的收藏视频
    async getAuthorCollectVideoPage() {
        this.collectVideoQuery.authorId = this.authorId
        getAuthorCollectVideoPage(this.collectVideoQuery).then(res => {
            this.collectVideoList = res.data.data
        })
    },
    // 播放视频
    playVideo(index) {
      const videoItem = this.videoList[index];
@@ -208,9 +295,12 @@
</script>
<style lang="scss" scoped>
body {
    background-color: #fff !important;
}
.container {
  padding-bottom: 20rpx;
  background-color: #f5f5f5;
  background-color: white;
  min-height: 100vh;
}
@@ -300,7 +390,7 @@
.tab-bar {
  display: flex;
  background-color: #fff;
  margin-bottom: 20rpx;
  padding-bottom: 20rpx;
}
.tab-item {
@@ -330,9 +420,10 @@
}
.video-list {
  display: flex;
  flex-wrap: wrap;
  width: calc(100% - 20rpx);
  padding: 0 10rpx;
  height: calc(100vh - 554rpx);
  background-color: #fff;
}
.video-item {
@@ -344,7 +435,7 @@
.video-cover {
  width: 100%;
  height: 350rpx;
  height: 500rpx;
  border-radius: 10rpx;
  display: block;
}
@@ -431,4 +522,9 @@
.user-header {
  position: relative;
}
.video-container {
    display: flex;
    flex-wrap: wrap
}
</style>