Explorar o código

添加 SideVideoCard 作为视频页面侧边栏的视频显示卡片

reghao %!s(int64=2) %!d(string=hai) anos
pai
achega
8209d3bc43

+ 111 - 0
src/components/card/SideVideoCard.vue

@@ -0,0 +1,111 @@
+<template>
+  <el-col style="padding-right: 7px; padding-left: 7px">
+    <div style="cursor: pointer" :title="video.title">
+      <el-card :body-style="{ padding: '0px' }" class="card">
+        <el-col :md="8">
+          <router-link :to="`/video/${video.videoId}`">
+            <div class="imgs">
+              <el-image
+                lazy
+                fit="cover"
+                :src="video.coverUrl"
+                class="coverImg"
+              />
+              <span style="position: absolute; bottom: 0; left: 0; color:white">
+                <i v-if="video.horizontal" class="el-icon-monitor" />
+                <i v-else class="el-icon-mobile-phone" />
+              </span>
+              <span style="position: absolute; bottom: 0; right: 0; color:white"> {{ video.duration }} </span>
+            </div>
+          </router-link>
+        </el-col>
+        <el-col :md="16">
+          <div style="padding: 14px">
+            <router-link :to="`/video/${video.videoId}`">
+              <span style="left: 0;margin-bottom: 0px;color: black;">{{ video.title | ellipsis }}</span>
+            </router-link>
+          </div>
+          <div style="padding: 14px">
+            <span style="left: 0;margin-bottom: 0px;color: black;">
+              <router-link target="_blank" :to="`/user/${video.user.userId}`">
+                <i class="el-icon-user"> {{ video.user.screenName | ellipsisUsername }} </i></router-link>
+            </span>
+          </div>
+          <div style="padding: 14px">
+            <el-col :md="6">
+              <span class="el-icon-video-play" style="left: 0;margin-bottom: 0px;color: black;">
+                {{ video.view }}
+              </span>
+            </el-col>
+            <el-col :md="6">
+              <span class="el-icon-s-comment" style="left: 0;margin-bottom: 0px;color: black;">
+                {{ video.comment }}
+              </span>
+            </el-col>
+          </div>
+        </el-col>
+      </el-card>
+    </div>
+  </el-col>
+</template>
+
+<script>
+export default {
+  name: 'SideVideoCard',
+  filters: {
+    ellipsis(value) {
+      if (!value) return ''
+      const max = 20
+      if (value.length > max) {
+        return value.slice(0, max) + '...'
+      }
+      return value
+    },
+    ellipsisUsername(value) {
+      if (!value) return ''
+      const max = 10
+      if (value.length > max) {
+        return value.slice(0, max) + '...'
+      }
+      return value
+    }
+  },
+  props: {
+    video: {
+      type: Object,
+      default: null
+    },
+    // 时间前的描述
+    dateTit: {
+      type: String,
+      default: ''
+    }
+  },
+  methods: {
+  }
+}
+</script>
+
+<style scoped>
+/*处于手机屏幕时*/
+@media screen and (max-width: 768px) {
+  .coverImg {
+    height: 80px !important;
+  }
+}
+
+.coverImg {
+  width: 100%;
+  height: 120px;
+  display: block;
+}
+
+.card {
+  margin-bottom: 20px;
+  transition: all 0.6s; /*所有属性变化在0.6秒内执行动画*/
+}
+
+.imgs {
+  position: relative;
+}
+</style>

+ 0 - 1
src/components/layout/NavBar.vue

@@ -173,7 +173,6 @@ import Vue from 'vue'
 import SearchBox from '@/components/layout/SearchBox'
 import { userMixin } from 'assets/js/mixin'
 import { getMyInfo } from '@/api/user'
-import VueCookies from "vue-cookies";
 
 export default {
   name: 'NavBar',

+ 44 - 44
src/utils/util.js

@@ -3,88 +3,88 @@
  * @param {*} timestamp  时间戳
  */
 const timestampToTime = (timestamp) => {
-    let date = new Date(timestamp) //时间戳为10位需*1000,时间戳为13位的话不需乘1000
-    let Y = date.getFullYear() + '-'
-    let M =
-        (date.getMonth() + 1 < 10 ?
-            '0' + (date.getMonth() + 1) :
-            date.getMonth() + 1) + '-'
-    let D =
+  const date = new Date(timestamp) // 时间戳为10位需*1000,时间戳为13位的话不需乘1000
+  const Y = date.getFullYear() + '-'
+  const M =
+        (date.getMonth() + 1 < 10
+          ? '0' + (date.getMonth() + 1)
+          : date.getMonth() + 1) + '-'
+  const D =
         (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '
-    let h =
+  const h =
         (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'
-    let m =
+  const m =
         (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) +
         ':'
-    let s =
+  const s =
         date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
-    return Y + M + D + h + m + s
-};
+  return Y + M + D + h + m + s
+}
 /**
  * 存储localStorage
  */
 const setStore = (name, content) => {
-    if (!name) return;
-    if (typeof content !== 'string') {
-        content = JSON.stringify(content);
-    }
-    window.localStorage.setItem(name, content);
+  if (!name) return
+  if (typeof content !== 'string') {
+    content = JSON.stringify(content)
+  }
+  window.localStorage.setItem(name, content)
 }
 
 /**
  * 获取localStorage
  */
 const getStore = name => {
-    if (!name) return;
-    return window.localStorage.getItem(name);
+  if (!name) return
+  return window.localStorage.getItem(name)
 }
 
 /**
  * 删除localStorage
  */
 const removeStore = name => {
-    if (!name) return;
-    window.localStorage.removeItem(name);
+  if (!name) return
+  window.localStorage.removeItem(name)
 }
 
 /**
  * 设置cookie
  **/
 function setCookie(name, value, day) {
-    let date = new Date();
-    date.setDate(date.getDate() + day);
-    document.cookie = name + '=' + value + ';expires=' + date;
-};
+  const date = new Date()
+  date.setDate(date.getDate() + day)
+  document.cookie = name + '=' + value + ';expires=' + date
+}
 
 /**
  * 获取cookie
  **/
 function getCookie(name) {
-    let reg = RegExp(name + '=([^;]+)');
-    let arr = document.cookie.match(reg);
-    if (arr) {
-        return arr[1];
-    } else {
-        return '';
-    }
-};
+  const reg = RegExp(name + '=([^;]+)')
+  const arr = document.cookie.match(reg)
+  if (arr) {
+    return arr[1]
+  } else {
+    return ''
+  }
+}
 
 /**
  * 删除cookie
  **/
 function delCookie(name) {
-    setCookie(name, null, -1);
-};
+  setCookie(name, null, -1)
+}
 
 /**
- * 导出 
+ * 导出
  **/
 export {
-    timestampToTime,
-    setStore,
-    getStore,
-    removeStore,
-    setCookie,
-    getCookie,
-    delCookie
-}
+  timestampToTime,
+  setStore,
+  getStore,
+  removeStore,
+  setCookie,
+  getCookie,
+  delCookie
+}

+ 6 - 0
src/utils/ws/socket-instance.js

@@ -1,5 +1,6 @@
 import WsSocket from '@/utils/ws/ws-socket'
 import { Notification } from 'element-ui'
+import Vue from 'vue'
 
 /**
  * SocketInstance 连接实例
@@ -18,6 +19,11 @@ class SocketInstance {
   constructor() {
     this.socket = new WsSocket(
       () => {
+        const userdata = Vue.$cookies.get('USERDATA')
+        if (userdata == null) {
+          return null
+        }
+
         const token = '1234567890'
         if (token === '') {
           return null

+ 1 - 1
src/views/home/MessageStream.vue

@@ -133,7 +133,7 @@ export default {
       }
     },
     reconnect() {
-      var that = this
+      const that = this
       if (that.lockReconnect) return
       that.lockReconnect = true
       // 没连接上会一直重连,设置延迟避免请求过多

+ 21 - 15
src/views/home/Search.vue

@@ -6,7 +6,7 @@
       separator-class="el-icon-arrow-right"
     >
       <el-breadcrumb-item>
-        对 <span class="result">{{keyword}}</span> 的搜索结果共有<span class="result"> {{ total }} </span>条记录
+        对 <span class="result">{{ keyword }}</span> 的搜索结果共有<span class="result"> {{ total }} </span>条记录
       </el-breadcrumb-item>
     </el-breadcrumb>
 
@@ -85,22 +85,28 @@ export default {
       this.$router.go(0)
     },
     videoQueryWrapper(keyword, pageNumber) {
-      videoQuery(keyword, pageNumber)
-        .then(res => {
-          if (res.code === 0) {
-            const resData = res.data
-            this.total = resData.totalSize
-            this.length = resData.totalPages
-            this.dataList = resData.list
+      videoQuery(keyword, pageNumber).then(resp => {
+        if (resp.code === 0) {
+          this.total = resp.data.totalSize
+          this.length = resp.data.totalPages
+          this.dataList = resp.data.list
 
-            if (this.total === 0) {
-              this.showEmpty = true
-            }
-          } else {
-            console.error(res.msg)
+          if (this.total === 0) {
+            this.showEmpty = true
           }
-        }).catch(error => {
-        console.error(error.message)
+        } else {
+          this.$notify.error({
+            message: resp.msg,
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify.error({
+          message: error.m,
+          type: 'error',
+          duration: 3000
+        })
       })
     }
   }

+ 682 - 0
src/views/home/VideoList.vue

@@ -0,0 +1,682 @@
+<template>
+  <el-row v-if="!permissionDenied" class="movie-list">
+    <el-col :md="15">
+      <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>
+            </el-row>
+          </div>
+          <div class="text item">
+            <div id="dplayer" ref="dplayer" style="height: 480px;" />
+          </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-collection"
+                :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="collection(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
+                v-if="video.cache != null"
+                type="danger"
+                size="mini"
+                icon="el-icon-download"
+                @click="cacheBiliVideo(video.videoId)"
+              >
+                <span>{{ video.cache.msg }}</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">
+        <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="videoComments"
+                :user="currentUser"
+                :props="props"
+                :before-submit="submit"
+                :before-like="like"
+                :before-delete="deleteComment"
+                :upload-img="uploadImg"
+              />
+            </div>
+          </div>
+        </el-card>
+      </el-row>
+    </el-col>
+    <el-col :md="9">
+      <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 v-if="showPlaylist" 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>
+              <el-row>
+                <span>自动播放 <el-switch v-model="autoPlay" /></span>
+              </el-row>
+            </div>
+            <div class="text item">
+              <el-table
+                :data="similarVideos"
+                style="width: 100%"
+              >
+                <el-table-column
+                  prop="title"
+                >
+                  <template slot-scope="scope">
+                    <router-link target="_blank" :to="`/video/${scope.row.videoId}`">
+                      <span>{{ scope.row.videoId }}</span>
+                    </router-link>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="coverUrl"
+                >
+                  <template slot-scope="scope">
+                    <span>10:00</span>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </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">
+              <el-row>
+                <h3>推荐视频</h3>
+              </el-row>
+              <el-row>
+                <span>自动播放 <el-switch v-model="autoPlay" /></span>
+              </el-row>
+            </div>
+            <div class="text item">
+              <el-row v-for="(item,index) in similarVideos" :key="index" class="item">
+                <video-card :video="item" />
+              </el-row>
+            </div>
+          </el-card>
+        </el-row>
+      </el-row>
+    </el-col>
+
+    <!-- 视频访问码对话框 -->
+    <el-dialog
+      append-to-body
+      :visible.sync="showAccessCodeDialog"
+      width="30%"
+      center
+    >
+      <el-card class="box-card">
+        <div slot="header" class="clearfix">
+          <span>输入视频访问码</span>
+          <el-button style="float: right; padding: 3px 0" type="text" @click="submitAccessCodeWrapper">提交</el-button>
+        </div>
+        <div class="text item">
+          <el-form ref="form" :model="accessCodeForm" label-width="80px">
+            <el-form-item label="访问码">
+              <el-input v-model="accessCodeForm.accessCode" style="width: 70%; padding-right: 2px" />
+            </el-form-item>
+          </el-form>
+        </div>
+      </el-card>
+    </el-dialog>
+
+    <!-- 视频报错对话框 -->
+    <el-dialog
+      append-to-body
+      :visible.sync="showErrorReportDialog"
+      width="30%"
+      center
+    >
+      <el-card class="box-card">
+        <div slot="header" class="clearfix">
+          <span>视频报错</span>
+          <el-button style="float: right; padding: 3px 0" type="text" @click="submitErrorReport">提交错误</el-button>
+        </div>
+        <div class="text item">
+          <el-form ref="form" :model="errorReportForm" label-width="80px">
+            <el-form-item label="错误类型">
+              <el-select v-model="errorReportForm.errorCode" placeholder="选择视频错误类型">
+                <el-option label="视频无封面" value="1" />
+                <el-option label="视频无声音" value="2" />
+                <el-option label="视频无画面" value="3" />
+                <el-option label="视频无资源" value="4" />
+                <el-option label="视频待删除" value="5" />
+              </el-select>
+            </el-form-item>
+          </el-form>
+        </div>
+      </el-card>
+    </el-dialog>
+  </el-row>
+  <el-row v-else>
+    <permission-denied-card :text-object="textObject" />
+  </el-row>
+</template>
+
+<script>
+import PermissionDeniedCard from '@/components/card/PermissionDeniedCard'
+import VideoCard from 'components/card/VideoCard'
+import UserAvatarCard from '@/components/card/UserAvatarCard'
+import comment from '@/components/comment'
+import SocketInstance from '@/utils/ws/socket-instance'
+
+import flvjs from 'flv.js'
+import DPlayer from 'dplayer'
+
+import { videoUrl, similarVideo, videoInfo, videoErrorReport, downloadVideo, cacheBiliVideo } from '@/api/video'
+import { collectItem } from '@/api/collect'
+import { getUserInfo } from '@/api/user'
+import { submitAccessCode } from '@/api/content'
+
+export default {
+  name: 'VideoList',
+  components: { VideoCard, UserAvatarCard, PermissionDeniedCard, comment },
+  data() {
+    return {
+      /** ********************************************************************/
+      wrapStyle: '',
+      videoComments: [],
+      currentUser: {
+        name: '草莓',
+        avatar: '//picx.zhimg.com/v2-a2c89378a6332cbfed3e28b5ab84feb7.jpg'
+      },
+      props: {
+        id: 114511,
+        content: 'this is comment content',
+        imgSrc: '//oss.reghao.cn/image/a/41e5094eac724efeb2675eea22dd4468.jpg',
+        children: [],
+        likes: 0,
+        liked: false,
+        reply: null,
+        createAt: 'createAt',
+        user: {
+          name: '芒果',
+          avatar: '//oss.reghao.cn/image/a/41e5094eac724efeb2675eea22dd4468.jpg'
+        }
+      },
+      // **********************************************************************/
+      video: null,
+      user: null,
+      similarVideos: [],
+      isCollected: false,
+      showAccessCodeDialog: false,
+      accessCodeForm: {
+        contentId: null,
+        contentType: 1002,
+        accessCode: null
+      },
+      showErrorReportDialog: false,
+      errorReportForm: {
+        videoId: null,
+        errorCode: null
+      },
+      permissionDenied: false,
+      textObject: {
+        content: '视频',
+        route: '/video'
+      },
+      showPlaylist: false,
+      autoPlay: false,
+      playList: {
+        current: 0,
+        list: [
+          'eyNXaDnmN3',
+          'WkYNYzDePp',
+          'a8Vx9EGDbA',
+          'a8V3D88NJK',
+          '4m7qMXapp1'
+        ]
+      },
+      // **********************************************************************/
+      flvjs,
+      DPlayer,
+      danmaku: {
+        api: '//api.reghao.cn/api/comment/danmaku/',
+        token: 'bili'
+      },
+      getUrl: true
+    }
+  },
+  watch: {
+    // 地址栏 url 发生变化时重新加载本页面
+    $route() {
+      this.$router.go()
+    }
+  },
+  created() {
+    const videoId = this.$route.params.id
+    this.accessCodeForm.contentId = videoId
+    this.getVideoInfo(videoId)
+    this.getSimilarVideos(videoId)
+  },
+  mounted() {
+    const header = this.$refs.header
+    if (header !== null) {
+      this.wrapStyle = `height: calc(100vh - ${header.clientHeight + 20}px)`
+    }
+  },
+  methods: {
+    // 获取视频的详细信息
+    getVideoInfo(videoId) {
+      videoInfo(videoId).then(resp => {
+        if (resp.code === 0) {
+          // this.showAccessCodeDialog = true
+          this.video = resp.data
+          document.title = resp.data.title
+          this.getVideoUrl(videoId)
+
+          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
+              })
+            }
+          })
+        } else if (resp.code === 2) {
+          this.$router.push('/404')
+        } else {
+          this.permissionDenied = true
+        }
+      }).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
+          this.playList.list = 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) {
+      const jsonData = {}
+      jsonData.contentType = 1002
+      jsonData.contentId = videoId
+      jsonData.collected = true
+      collectItem(jsonData).then(resp => {
+        if (resp.code !== 0) {
+          this.$notify.success({
+            title: '视频收藏失败',
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      })
+    },
+    getDownloadUrl(videoId) {
+      // let filename
+      downloadVideo(videoId).then(resp => {
+        if (resp.code === 0) {
+          const downloadUrl = resp.data.url
+          window.open(downloadUrl, '_blank')
+        } else {
+          this.$notify({
+            title: '提示',
+            message: resp.msg,
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify({
+          title: '提示',
+          message: error.message,
+          type: 'error',
+          duration: 3000
+        })
+      })
+    },
+    cacheBiliVideo(bvId) {
+      cacheBiliVideo(bvId).then(resp => {
+        if (resp.code === 0) {
+          const resData = resp.data
+          this.$notify({
+            title: '提示',
+            message: resData.msg,
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      })
+    },
+    submitAccessCodeWrapper() {
+      submitAccessCode(this.accessCodeForm).then(resp => {
+        if (resp.code === 0) {
+          this.video = resp.data
+        } else {
+          this.$notify({
+            message: resp.msg,
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify({
+          title: '提示',
+          message: error.message,
+          type: 'warning',
+          duration: 3000
+        })
+      })
+    },
+    displayErrorReportDialog() {
+      this.errorReportForm.videoId = this.video.videoId
+      this.showErrorReportDialog = true
+    },
+    submitErrorReport() {
+      this.showErrorReportDialog = false
+      videoErrorReport(this.errorReportForm).then(resp => {
+        if (resp.code === 0) {
+          this.$notify({
+            title: '提示',
+            message: '视频错误已提交',
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify({
+          title: '提示',
+          message: error.message,
+          type: 'warning',
+          duration: 3000
+        })
+      })
+    },
+    // ****************************************************************************************************************
+    getVideoUrl(videoId) {
+      videoUrl(videoId).then(res => {
+        if (res.code === 0) {
+          SocketInstance.connect()
+
+          const urlType = res.data.type
+          if (urlType === 'mp4') {
+            const urls = res.data.urls
+            for (const url of urls) {
+              url.type = 'normal'
+            }
+            const autoPlay = false
+            this.initMp4Player(this.video.userId, videoId, this.video.coverUrl, urls, res.data.currentTime, autoPlay)
+          } else {
+            this.$notify.error({
+              message: '视频 url 类型不合法',
+              type: 'warning',
+              duration: 3000
+            })
+          }
+        } else {
+          this.$notify.error({
+            message: '视频 url 获取失败',
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify.error({
+          message: error.message,
+          type: 'error',
+          duration: 3000
+        })
+      })
+    },
+    initMp4Player(userId, videoId, coverUrl, urls, pos, autoPlay) {
+      const player = new DPlayer({
+        container: document.querySelector('#dplayer'),
+        lang: 'zh-cn',
+        logo: '/logo.png',
+        screenshot: false,
+        autoplay: autoPlay,
+        volume: 0.1,
+        mutex: true,
+        video: {
+          pic: coverUrl,
+          defaultQuality: 0,
+          quality: urls,
+          hotkey: true
+        },
+        danmaku: {
+          id: videoId,
+          maximum: 10000,
+          api: this.danmaku.api,
+          token: this.danmaku.token,
+          user: userId,
+          bottom: '15%',
+          unlimited: true
+        }
+      })
+
+      // 设置音量
+      // player.volume(0.1, true, false)
+      // 跳转到上次看到的位置
+      player.seek(pos)
+
+      /* 事件绑定 */
+      player.on('progress', function() {
+        const jsonData = {}
+        jsonData.videoId = videoId
+        jsonData.currentTime = player.video.currentTime
+        SocketInstance.send(jsonData)
+      })
+
+      player.on('ended', () => {
+        const jsonData = {}
+        jsonData.videoId = videoId
+        jsonData.currentTime = player.video.currentTime
+        SocketInstance.send(jsonData)
+
+        const nextPath = this.getNextPath()
+        if (nextPath !== null) {
+          console.log('播放下一个视频')
+          this.$router.push(nextPath)
+        } else {
+          console.log('视频播放完成')
+        }
+      })
+
+      player.on('volumechange', () => {
+        console.log('声音改变')
+      })
+    },
+    getNextPath() {
+      let current = this.playList.current
+      if (current !== this.playList.list.length) {
+        current += 1
+        return this.playList.list[current]
+      }
+
+      return null
+    },
+    // ****************************************************************************************************************
+    async submit(newComment, parent, add) {
+      const res = await new Promise((resolve) => {
+        setTimeout(() => {
+          resolve({ newComment, parent })
+        }, 300)
+      })
+      add(Object.assign(res.newComment, { _id: new Date().getTime() }))
+      console.log('addComment: ', res)
+    },
+    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 {
+    padding-top: 8px;
+    padding-left: 0.5%;
+    padding-right: 0.5%;
+  }
+}
+
+.movie-list {
+  padding-top: 15px;
+  padding-left: 5%;
+  padding-right: 5%;
+}
+
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  content: "";
+}
+
+.clearfix:after {
+  clear: both;
+}
+
+.v-tag {
+  padding-top: 10px;
+}
+.tag{
+  margin-right: 3px;
+}
+</style>

+ 20 - 55
src/views/home/VideoPage.vue

@@ -127,58 +127,21 @@
         <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 v-if="showPlaylist" 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>
-              <el-row>
-                <span>自动播放 <el-switch v-model="autoPlay" /></span>
-              </el-row>
-            </div>
-            <div class="text item">
-              <el-table
-                :data="similarVideos"
-                style="width: 100%"
-              >
-                <el-table-column
-                  prop="title"
-                >
-                  <template slot-scope="scope">
-                    <router-link target="_blank" :to="`/video/${scope.row.videoId}`">
-                      <span>{{ scope.row.videoId }}</span>
-                    </router-link>
-                  </template>
-                </el-table-column>
-                <el-table-column
-                  prop="coverUrl"
-                >
-                  <template slot-scope="scope">
-                    <span>10:00</span>
-                  </template>
-                </el-table-column>
-              </el-table>
-            </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">
-              <el-row>
-                <h3>推荐视频</h3>
-              </el-row>
-              <el-row>
-                <span>自动播放 <el-switch v-model="autoPlay" /></span>
-              </el-row>
-            </div>
-            <div class="text item">
-              <el-row v-for="(item,index) in similarVideos" :key="index" class="item">
-                <video-card :video="item" />
-              </el-row>
-            </div>
-          </el-card>
-        </el-row>
+      </el-row>
+      <el-row v-if="showPlaylist" 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>
+            <el-row>
+              <span>自动播放 <el-switch v-model="autoPlay" /></span>
+            </el-row>
+          </div>
+        </el-card>
+      </el-row>
+      <el-row v-for="(item,index) in similarVideos" :key="index" style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
+        <side-video-card :video="item" />
       </el-row>
     </el-col>
 
@@ -240,7 +203,7 @@
 <script>
 import PermissionDeniedCard from '@/components/card/PermissionDeniedCard'
 import VideoPlayer from 'components/VideoPlayer'
-import VideoCard from 'components/card/VideoCard'
+import SideVideoCard from 'components/card/SideVideoCard'
 import UserAvatarCard from '@/components/card/UserAvatarCard'
 import comment from '@/components/comment'
 
@@ -251,7 +214,7 @@ import { submitAccessCode } from '@/api/content'
 
 export default {
   name: 'VideoPage',
-  components: { VideoCard, VideoPlayer, UserAvatarCard, PermissionDeniedCard, comment },
+  components: { SideVideoCard, VideoPlayer, UserAvatarCard, PermissionDeniedCard, comment },
   data() {
     return {
       /** ********************************************************************/
@@ -319,7 +282,9 @@ export default {
   },
   mounted() {
     const header = this.$refs.header
-    this.wrapStyle = `height: calc(100vh - ${header.clientHeight + 20}px)`
+    if (header !== null) {
+      this.wrapStyle = `height: calc(100vh - ${header.clientHeight + 20}px)`
+    }
   },
   methods: {
     // 获取视频的详细信息