Parcourir la source

更新 /shortvideo 页面

reghao il y a 1 an
Parent
commit
19cbe9b68d
2 fichiers modifiés avec 570 ajouts et 63 suppressions
  1. 3 3
      src/api/video.js
  2. 567 60
      src/views/home/ShortVideo.vue

+ 3 - 3
src/api/video.js

@@ -12,7 +12,7 @@ const videoApi = {
 
   videoCategoryApi: '/api/content/video/categories',
   categoryVideoApi: '/api/content/video/category',
-  categoryShortVideoApi: '/api/content/video/category/short',
+  categoryShortVideoApi: '/api/content/video/short',
   userVideoPostApi: '/api/content/video/user',
   tagVideoPostApi: '/api/content/video/tag',
   videoInfoApi: '/api/content/video/detail',
@@ -101,8 +101,8 @@ export function categoryVideos(categoryId, page) {
   return get(videoApi.categoryVideoApi + '?categoryId=' + categoryId + '&page=' + page)
 }
 
-export function categoryShortVideos(categoryId, page) {
-  return get(videoApi.categoryShortVideoApi + '?categoryId=' + categoryId + '&page=' + page)
+export function getShortVideo() {
+  return get(videoApi.categoryShortVideoApi)
 }
 
 // 获取用户视频

+ 567 - 60
src/views/home/ShortVideo.vue

@@ -1,74 +1,318 @@
 <template>
-  <div>
-    <el-row id="movie-list">
-      <el-scrollbar style="width: 100%; height: 75vh;">
-        <el-row
-          v-if="dataList.length !== 0"
-          v-infinite-scroll="load"
-          infinite-scroll-disabled="loading"
-          infinite-scroll-distance="10"
-        >
-          <el-col v-for="(video, index) in dataList" :key="index" :md="6" :sm="12" :xs="12">
-            <video-card :video="video" />
-          </el-col>
-          <el-col v-if="dataList.length === 0" class="not-result" :md="6" :sm="12" :xs="12">
-            <img src="@/assets/img/icon/not-result.png">
-            <div>没有视频数据</div>
-          </el-col>
-        </el-row>
-      </el-scrollbar>
-    </el-row>
-  </div>
+  <el-row v-if="video !== null" class="movie-list">
+    <el-col :md="12">
+      <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <el-row>
+              <h3 v-html="video.title" />
+            </el-row>
+            <el-row style="color: #999;font-size: 16px;padding-top: 0px;">
+              <span><i class="el-icon-video-play">{{ video.view }}</i></span>
+              <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
+              <span><i class="el-icon-s-comment">{{ video.comment }}</i></span>
+              <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
+              <span><i class="el-icon-watch">{{ video.pubDate }}</i></span>
+              <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
+              <span v-if="videoId !== null && videoId.includes('BV')"><i class="el-icon-apple">
+                  <a target="_blank" :href="`https://bilibili.com/` + videoId">bili</a>
+                </i></span>
+            </el-row>
+          </div>
+          <div class="text item">
+            <video-player :video-prop="video" />
+          </div>
+        </el-card>
+      </el-row>
+      <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <div class="video-data-row">
+              <el-button
+                type="danger"
+                size="mini"
+                icon="el-icon-plus"
+                :disabled="isCollected"
+                @click="collection(video.videoId)"
+              >
+                <span>收藏 {{ video.favorite }}</span>
+              </el-button>
+              <el-button
+                type="danger"
+                size="mini"
+                icon="el-icon-thumb"
+                :disabled="isCollected"
+                @click="collection(video.videoId)"
+              >
+                <span>喜欢 {{ video.thumbUp }}</span>
+              </el-button>
+              <el-button
+                type="danger"
+                size="mini"
+                icon="el-icon-share"
+                :disabled="isCollected"
+                @click="getShareUrl(video.videoId)"
+              >
+                <span>分享 {{ video.share }}</span>
+              </el-button>
+              <el-button
+                type="danger"
+                size="mini"
+                icon="el-icon-download"
+                @click="getDownloadUrl(video.videoId)"
+              >
+                <span>下载</span>
+              </el-button>
+              <el-button
+                type="danger"
+                size="mini"
+                icon="el-icon-help"
+                @click="displayErrorReportDialog"
+              >
+                <span>报错</span>
+              </el-button>
+            </div>
+          </div>
+          <div class="text item">
+            <!--视频描述行-->
+            <span class="description" v-html="video.description" />
+            <el-divider />
+            <!--视频标签行-->
+            <div class="v-tag">
+              <el-tag
+                v-for="(tag,index) in video.tags"
+                :key="index"
+                class="tag"
+                size="medium"
+                effect="plain"
+              >
+                <router-link target="_blank" :to="`/video/tag/` + tag">
+                  {{ tag }}
+                </router-link>
+              </el-tag>
+            </div>
+          </div>
+        </el-card>
+      </el-row>
+      <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
+        <user-avatar-card v-if="user !== null" :user-avatar="user" />
+      </el-row>
+      <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <el-row>
+              <h3>视频评论</h3>
+            </el-row>
+          </div>
+          <div class="text item">
+            <div ref="comment" :style="wrapStyle" class="comment-wrap">
+              <comment
+                v-model="dataList"
+                :user="currentUser"
+                :props="props"
+                :before-submit="submit"
+                :before-like="like"
+                :before-delete="deleteComment"
+                :upload-img="uploadImg"
+              />
+              <el-pagination
+                :small="screenWidth <= 768"
+                hide-on-single-page
+                layout="prev, pager, next"
+                :page-size="pageSize"
+                :current-page="currentPage"
+                :total="totalSize"
+                @current-change="handleCurrentChange"
+              />
+            </div>
+          </div>
+        </el-card>
+      </el-row>
+    </el-col>
+
+    <!-- 添加到播放列表对话框 -->
+    <el-dialog
+      append-to-body
+      :visible.sync="showPlaylistDialog"
+      width="30%"
+      center
+    >
+      <el-card class="box-card">
+        <div slot="header" class="clearfix">
+          <el-button style="float: right; padding: 3px 0" type="text" @click="createAlbum">
+            创建播放列表
+          </el-button>
+          <el-form v-if="showCreateAlbum" ref="form" :model="albumForm" label-width="80px">
+            <el-form-item>
+              <el-input v-model="albumForm.albumName" style="padding-right: 1px" placeholder="标题不能超过 50 个字符" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="plain" @click="onCreateAlbum">确定</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="text item">
+          <el-table
+            :data="playlist"
+            border
+            style="width: 100%"
+          >
+            <el-table-column
+              prop="albumName"
+              label="播放列表"
+            />
+            <el-table-column
+              prop="total"
+              label="数量"
+            />
+            <el-table-column label="收藏" width="80" align="center">
+              <template slot-scope="scope">
+                <el-button
+                  type="danger"
+                  size="mini"
+                  icon="el-icon-plus"
+                  @click="addToPlaylist(scope.row)"
+                />
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </el-card>
+    </el-dialog>
+  </el-row>
 </template>
 
 <script>
-import VideoCard from 'components/card/VideoCard'
-import { categoryShortVideos } from '@/api/video'
+import VideoPlayer from 'components/VideoPlayer'
+import UserAvatarCard from '@/components/card/UserAvatarCard'
+import comment from '@/components/comment'
+
+import { similarVideo, videoErrorReport, downloadVideo, getShortUrl, getShortVideo } from '@/api/video'
+import { collectItem, createAlbum, getUserPlaylist } from '@/api/collect'
+import { getUserInfo } from '@/api/user'
+import { publishComment, getComment } from '@/api/comment'
+import { getAuthedUser } from '@/utils/auth'
 
 export default {
   name: 'ShortVideo',
-  components: { VideoCard },
+  components: { VideoPlayer, UserAvatarCard, comment },
   data() {
     return {
       // 屏幕宽度, 为了控制分页条的大小
       screenWidth: document.body.clientWidth,
       currentPage: 1,
-      pageSize: 12,
+      pageSize: 20,
       totalSize: 0,
       dataList: [],
-      categoryId: 1,
-      treeNode: [],
-      defaultProps: {
+      // ********************************************************************/
+      wrapStyle: '',
+      videoComments: [
+        {
+          commentId: 114511,
+          content: 'this is comment content',
+          imageUrl: '',
+          children: [],
+          likes: 0,
+          liked: false,
+          reply: null,
+          createAt: 1700271326393,
+          user: {
+            userId: 1,
+            name: '西瓜',
+            avatar: ''
+          }
+        }
+      ],
+      currentUser: {
+        userId: 9999,
+        name: '芒果',
+        avatar: '//picx.zhimg.com/v2-a2c89378a6332cbfed3e28b5ab84feb7.jpg',
+        author: true
+      },
+      // 自定义组件中 comment 对象的字段名
+      props: {
+        id: 'commentId',
+        content: 'content',
+        imgSrc: 'imageUrl',
         children: 'children',
-        label: 'label',
-        value: 'value'
+        likes: 'likes',
+        liked: 'liked',
+        reply: 'reply',
+        createAt: 'createAt',
+        total: 'total',
+        user: 'user'
       },
-      loading: false
+      // ********************************************************************/
+      videoId: null,
+      video: null,
+      user: null,
+      similarVideos: [],
+      isCollected: false,
+      showPlaylistDialog: false,
+      playlist: [],
+      accessCodeForm: {
+        contentId: null,
+        contentType: 1002,
+        accessCode: null
+      },
+      showErrorReportDialog: false,
+      errorReportForm: {
+        videoId: null,
+        errorCode: null
+      },
+      permissionDenied: false,
+      textObject: {
+        content: '视频',
+        route: '/video'
+      },
+      autoPlay: false,
+      showCreateAlbum: false,
+      albumForm: {
+        albumName: null
+      }
+    }
+  },
+  watch: {
+    // 地址栏 url 发生变化时重新加载本页面
+    $route() {
+      this.$router.go()
     }
   },
   created() {
-    document.title = '短视频主页'
-    this.videoPageWrapper(this.categoryId, this.currentPage)
+    const loginUser = getAuthedUser()
+    if (loginUser != null) {
+      this.currentUser = {
+        userId: loginUser.userId,
+        name: loginUser.screenName,
+        avatar: loginUser.avatarUrl,
+        author: true
+      }
+    }
+
+    this.getVideoInfo()
+    // this.getSimilarVideos(this.videoId)
+    // this.getCommentWrapper(this.currentPage)
   },
   mounted() {
-    // 当窗口宽度改变时获取屏幕宽度
-    window.onresize = () => {
-      return () => {
-        window.screenWidth = document.body.clientWidth
-        this.screenWidth = window.screenWidth
-      }
+    const header = this.$refs.header
+    if (header !== undefined && header !== null) {
+      this.wrapStyle = `height: calc(100vh - ${header.clientHeight + 20}px)`
     }
   },
   methods: {
-    videoPageWrapper(categoryId, currentPage) {
-      categoryShortVideos(categoryId, currentPage).then(resp => {
+    // ****************************************************************************************************************
+    handleCurrentChange(currentPage) {
+      this.currentPage = currentPage
+      this.getCommentWrapper(currentPage)
+      // 回到顶部
+      scrollTo(0, 0)
+    },
+    getCommentWrapper(pageNumber) {
+      getComment(this.videoId, pageNumber).then(resp => {
         if (resp.code === 0) {
-          for (const item of resp.data.list) {
-            this.dataList.push(item)
-          }
-
-          this.currentPage += 1
-          this.loading = false
+          const respData = resp.data
+          this.dataList = respData.list
+          this.totalSize = respData.totalSize
         } else {
           this.$notify({
             title: '提示',
@@ -86,35 +330,298 @@ export default {
         })
       })
     },
-    load() {
-      this.loading = true
-      setTimeout(() => {
-        this.videoPageWrapper(this.categoryId, this.currentPage)
-      }, 1000)
+    // ****************************************************************************************************************
+    // 获取视频的详细信息
+    getVideoInfo() {
+      getShortVideo().then(resp => {
+        if (resp.code === 0) {
+          this.video = resp.data
+          this.videoId = resp.data.videoId
+          document.title = resp.data.title
+          this.userId = resp.data.userId
+          getUserInfo(this.userId).then(resp => {
+            if (resp.code === 0) {
+              this.user = resp.data
+            } else {
+              this.$notify.error({
+                message: '用户数据获取失败',
+                type: 'warning',
+                duration: 3000
+              })
+            }
+          })
+        }
+      }).catch(error => {
+        this.$notify.error({
+          message: error.message,
+          type: 'warning',
+          duration: 3000
+        })
+      })
+    },
+    // 获取和当前视频类似的其他视频
+    getSimilarVideos(videoId) {
+      similarVideo(videoId).then(resp => {
+        if (resp.code === 0) {
+          this.similarVideos = resp.data
+        } else {
+          this.$notify.error({
+            message: '推荐视频数据获取失败',
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify.error({
+          message: error.message,
+          type: 'warning',
+          duration: 3000
+        })
+      })
+    },
+    // 换一换
+    refreshSimilar() {
+      console.log('刷新相关推荐')
+    },
+    // 用户点击收藏
+    collection(videoId) {
+      this.showPlaylistDialog = true
+      const queryInfo = {
+        pn: 1,
+        userId: this.currentUser.userId
+      }
+      getUserPlaylist(queryInfo).then(resp => {
+        if (resp.code === 0) {
+          this.playlist = resp.data.list
+        }
+      })
+    },
+    addToPlaylist(row) {
+      this.showPlaylistDialog = false
+      const jsonData = {}
+      jsonData.albumId = row.albumId
+      jsonData.postId = this.videoId
+      jsonData.action = 1
+      collectItem(jsonData).then(resp => {
+        if (resp.code === 0) {
+          this.$notify.success({
+            title: '视频已收藏',
+            type: 'success',
+            duration: 3000
+          })
+        } else {
+          this.$notify.warning({
+            title: '视频收藏失败',
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      })
+    },
+    getShareUrl(videoId) {
+      getShortUrl(videoId).then(resp => {
+        if (resp.code === 0) {
+          console.log(resp.data)
+          this.video.share += 1
+        }
+      })
+    },
+    getDownloadUrl(videoId) {
+      // let filename
+      downloadVideo(videoId).then(resp => {
+        if (resp.code === 0) {
+          const downloadUrl = resp.data.url
+          window.open(downloadUrl, '_blank')
+          /* fetch(downloadUrl.url, {
+            headers: {
+              Authorization: 'Bearer ' + downloadUrl.token
+            },
+            method: 'GET',
+            credentials: 'include'
+          }).then(resp => {
+            /!*
+            遍历 formdata
+            for (const key of resp.headers.keys()) {
+              console.log(key + ' : ' + resp.headers.get(key))
+            }*!/
+            const header = resp.headers.get('Content-Disposition')
+            const parts = header.split(';')
+            const encodeFilename = parts[1].split('=')[1]
+            filename = decodeURI(encodeFilename)
+            return resp.blob()
+          }).then(data => {
+            const blobUrl = window.URL.createObjectURL(data)
+            const a = document.createElement('a')
+            a.download = filename
+            a.href = blobUrl
+            a.click()
+          }).catch(e => {
+            this.$notify({
+              title: '提示',
+              message: '视频下载失败',
+              type: 'warning',
+              duration: 3000
+            })
+          })*/
+        } else {
+          this.$notify({
+            title: '提示',
+            message: resp.msg,
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify({
+          title: '提示',
+          message: error.message,
+          type: 'error',
+          duration: 3000
+        })
+      })
+    },
+    createAlbum() {
+      this.showCreateAlbum = true
+    },
+    onCreateAlbum() {
+      this.showCreateAlbum = false
+      createAlbum(this.albumForm).then(resp => {
+        if (resp.code === 0) {
+          this.playlist.push(resp.data)
+        }
+      })
+      this.albumForm.albumName = null
+    },
+    displayErrorReportDialog() {
+      this.errorReportForm.videoId = this.video.videoId
+      this.showErrorReportDialog = true
+    },
+    submitErrorReport() {
+      this.showErrorReportDialog = false
+      videoErrorReport(this.errorReportForm).then(resp => {
+        if (resp.code === 0) {
+          this.errorReportForm.errorCode = null
+          this.$notify({
+            title: '提示',
+            message: '视频错误已提交',
+            type: 'warning',
+            duration: 3000
+          })
+        } else {
+          this.$notify({
+            title: '提示',
+            message: resp.msg,
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify({
+          title: '提示',
+          message: error.message,
+          type: 'warning',
+          duration: 3000
+        })
+      })
+    },
+    // ****************************************************************************************************************
+    // 评论
+    async submit(newComment, parent, add) {
+      const res = await new Promise((resolve) => {
+        setTimeout(() => {
+          resolve({ newComment, parent })
+        }, 300)
+      })
+
+      add(Object.assign(res.newComment, { postId: this.video.videoId }))
+      if (res.parent !== null) {
+        // console.log('parent: ', res.parent)
+      } else {
+        this.totalSize += 1
+      }
+
+      // console.log('addComment: ', res)
+      publishComment(res).then(resp => {
+        if (resp.code === 0) {
+          this.$notify.success({
+            message: '评论已发布',
+            duration: 3000
+          })
+        } else {
+          this.$notify.warning({
+            message: '评论发布失败',
+            duration: 3000
+          })
+        }
+      })
+    },
+    async like(comment) {
+      const res = await new Promise((resolve) => {
+        setTimeout(() => {
+          resolve(comment)
+        }, 0)
+      })
+
+      console.log('likeComment: ', res)
+    },
+    async uploadImg({ file, callback }) {
+      const res = await new Promise((resolve, reject) => {
+        const reader = new FileReader()
+        reader.readAsDataURL(file)
+        reader.onload = () => {
+          resolve(reader.result)
+        }
+
+        reader.onerror = () => {
+          reject(reader.error)
+        }
+      })
+      callback(res)
+      console.log('uploadImg: ', res)
+    },
+    async deleteComment(comment, parent) {
+      const res = await new Promise((resolve) => {
+        setTimeout(() => {
+          resolve({ comment, parent })
+        }, 300)
+      })
+      console.log('deleteComment: ', res)
     }
+    // ****************************************************************************************************************
   }
 }
 </script>
 
 <style scoped>
 /*处于手机屏幕时*/
-@media screen and (max-width: 768px){
-  #movie-list {
+@media screen and (max-width: 768px) {
+  .movie-list {
     padding-top: 8px;
     padding-left: 0.5%;
     padding-right: 0.5%;
   }
 }
 
-#movie-list {
+.movie-list {
   padding-top: 15px;
-  padding-left: 6%;
-  padding-right: 6%;
+  padding-left: 5%;
+  padding-right: 5%;
+}
+
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  content: "";
+}
+
+.clearfix:after {
+  clear: both;
 }
 
-.not-result {
-  padding-top: 100px;
-  padding-bottom: 100px;
-  text-align: center;
+.v-tag {
+  padding-top: 10px;
+}
+.tag{
+  margin-right: 3px;
 }
 </style>