|
|
@@ -1,1148 +1,303 @@
|
|
|
<template>
|
|
|
- <el-row v-if="!permissionDenied" class="movie-list">
|
|
|
- <el-row v-if="video !== null">
|
|
|
- <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="' '" />
|
|
|
- <span><i class="el-icon-s-comment">{{ video.comment }}</i></span>
|
|
|
- <span v-html="' '" />
|
|
|
- <span><i class="el-icon-watch">{{ video.pubDate }}</i></span>
|
|
|
- <span v-html="' '" />
|
|
|
- <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>
|
|
|
- <span v-html="' '" />
|
|
|
- <span><i class="el-icon-view">{{ realtimeViewCount }} 正在观看</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="tag">
|
|
|
- <el-button
|
|
|
- type="success"
|
|
|
- size="mini"
|
|
|
- icon="el-icon-plus"
|
|
|
- :disabled="isCollected"
|
|
|
- class="tag"
|
|
|
- @click="collection(video.videoId)"
|
|
|
- >
|
|
|
- <span>收藏 {{ video.favorite }}</span>
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- type="success"
|
|
|
- size="mini"
|
|
|
- icon="el-icon-thumb"
|
|
|
- :disabled="isCollected"
|
|
|
- class="tag"
|
|
|
- @click="likeVideo(video)"
|
|
|
- >
|
|
|
- <span>喜欢 {{ video.thumbUp }}</span>
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- type="success"
|
|
|
- size="mini"
|
|
|
- icon="el-icon-thumb"
|
|
|
- class="tag"
|
|
|
- @click="dislikeVideoWrapper(video)"
|
|
|
- >
|
|
|
- <span>不喜欢 {{ video.thumbUp }}</span>
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- type="success"
|
|
|
- size="mini"
|
|
|
- icon="el-icon-share"
|
|
|
- :disabled="isCollected"
|
|
|
- class="tag"
|
|
|
- @click="displayShareVideoDialog"
|
|
|
- >
|
|
|
- <span>分享 {{ video.share }}</span>
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- type="success"
|
|
|
- size="mini"
|
|
|
- icon="el-icon-download"
|
|
|
- class="tag"
|
|
|
- @click="getDownloadUrl(video.videoId)"
|
|
|
- >
|
|
|
- <span>下载</span>
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- type="warning"
|
|
|
- size="mini"
|
|
|
- icon="el-icon-help"
|
|
|
- class="tag"
|
|
|
- @click="displayErrorReportDialog"
|
|
|
- >
|
|
|
- <span>报错</span>
|
|
|
- </el-button>
|
|
|
- <div v-if="showEdit">
|
|
|
- <el-button
|
|
|
- type="danger"
|
|
|
- size="mini"
|
|
|
- icon="el-icon-delete"
|
|
|
- class="tag"
|
|
|
- @click="deleteVideo(video)"
|
|
|
- >
|
|
|
- <span>删除</span>
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- type="danger"
|
|
|
- size="mini"
|
|
|
- icon="el-icon-edit"
|
|
|
- class="tag"
|
|
|
- @click="displayEditDialog"
|
|
|
- >
|
|
|
- <span>编辑</span>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
+ <el-row v-if="!permissionDenied" class="video-page-container">
|
|
|
+ <el-row v-if="video !== null" :gutter="20">
|
|
|
+ <el-col :md="16" :lg="17">
|
|
|
+ <div class="player-section shadow-box">
|
|
|
+ <div class="video-header">
|
|
|
+ <h1 class="video-title" v-html="video.title" />
|
|
|
+ <div class="video-meta">
|
|
|
+ <div class="meta-left">
|
|
|
+ <span class="meta-item"><i class="el-icon-video-play"></i> {{ video.view }} 次播放</span>
|
|
|
+ <span class="meta-item"><i class="el-icon-s-comment"></i> {{ video.comment }} 评论</span>
|
|
|
+ <span class="meta-item"><i class="el-icon-watch"></i> {{ video.pubDate }}</span>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div class="text item">
|
|
|
- <!--视频描述行-->
|
|
|
- <div>
|
|
|
- <span v-html="video.description" />
|
|
|
- </div>
|
|
|
- <el-divider />
|
|
|
- <!--视频标签行-->
|
|
|
- <div>
|
|
|
- <el-tag
|
|
|
- v-for="(tag,index) in video.tags"
|
|
|
- :key="index"
|
|
|
- class="tag"
|
|
|
- size="medium"
|
|
|
- effect="plain"
|
|
|
- >
|
|
|
- <router-link style="text-decoration-line: none" target="_blank" :to="`/video/tag/` + tag">
|
|
|
- {{ tag }}
|
|
|
- </router-link>
|
|
|
+ <div class="meta-right">
|
|
|
+ <el-tag v-if="videoId && videoId.includes('BV')" size="mini" type="info" effect="plain">
|
|
|
+ <a target="_blank" :href="'https://bilibili.com/' + videoId" class="bili-link">B站源</a>
|
|
|
+ </el-tag>
|
|
|
+ <el-tag type="danger" size="small" effect="dark" class="live-tag">
|
|
|
+ <i class="el-icon-view"></i> {{ realtimeViewCount }} 人正在看
|
|
|
</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="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 class="video-content">
|
|
|
+ <video-player-card
|
|
|
+ v-if="video"
|
|
|
+ :video-id="videoId"
|
|
|
+ :video-data="video"
|
|
|
+ :user-token="userToken"
|
|
|
+ :send-event="sendEvent"
|
|
|
+ @update-view-count="val => realtimeViewCount = val"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <video-ops-card
|
|
|
+ v-if="video"
|
|
|
+ :video="video"
|
|
|
+ :show-edit="showEdit"
|
|
|
+ @like="likeVideo"
|
|
|
+ @dislike="dislikeVideoWrapper"
|
|
|
+ @collect="collection"
|
|
|
+ @share="displayShareVideoDialog"
|
|
|
+ @download="getDownloadUrl"
|
|
|
+ @report="displayErrorReportDialog"
|
|
|
+ @edit="displayEditDialog"
|
|
|
+ @delete="deleteVideo"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-card class="info-card shadow-box">
|
|
|
+ <div class="video-description" v-html="video.description"></div>
|
|
|
+ <div class="video-tags">
|
|
|
+ <el-tag v-for="(tag,index) in video.tags" :key="index" class="video-tag-item" size="small" effect="light" round>
|
|
|
+ <router-link :to="'/video/tag/' + tag"># {{ tag }}</router-link>
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <user-comment-card v-if="videoId" :video-id="videoId" :current-user="currentUser" :screen-width="screenWidth" />
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :md="8" :lg="7">
|
|
|
+ <div class="side-container">
|
|
|
+ <user-avatar-card v-if="user" :user-avatar="user" class="shadow-box mb-20" />
|
|
|
+ <el-card class="recommend-card shadow-box">
|
|
|
+ <div slot="header" class="recommend-header">
|
|
|
+ <span class="title">接下来播放</span>
|
|
|
+ <div class="auto-play">
|
|
|
+ <span>自动播放</span>
|
|
|
+ <el-switch v-model="autoPlay" size="mini" />
|
|
|
</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>
|
|
|
- <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 class="recommend-list">
|
|
|
+ <div v-for="(item,index) in similarVideos" :key="index" class="side-card-wrapper">
|
|
|
+ <side-video-card :video="item" />
|
|
|
+ </div>
|
|
|
</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>
|
|
|
+ </div>
|
|
|
</el-col>
|
|
|
|
|
|
- <!-- 添加到播放列表对话框 -->
|
|
|
- <el-dialog
|
|
|
- append-to-body
|
|
|
- :visible.sync="showPlaylistDialog"
|
|
|
- center
|
|
|
- >
|
|
|
- <el-card class="box-card">
|
|
|
- <div slot="header" class="clearfix">
|
|
|
- <span>添加到收藏夹</span>
|
|
|
- <el-button style="float: right; padding: 3px 0" type="text" @click="addToPlaylist">确定</el-button>
|
|
|
- </div>
|
|
|
- <div class="text item">
|
|
|
- <el-table
|
|
|
- ref="singleTable"
|
|
|
- :data="playlist"
|
|
|
- highlight-current-row
|
|
|
- style="width: 100%"
|
|
|
- @current-change="handleCurrentRow"
|
|
|
- >
|
|
|
- <el-table-column
|
|
|
- type="index"
|
|
|
- />
|
|
|
- <el-table-column
|
|
|
- prop="albumName"
|
|
|
- />
|
|
|
- <el-table-column
|
|
|
- prop="total"
|
|
|
- />
|
|
|
- <el-table-column
|
|
|
- prop="total"
|
|
|
- />
|
|
|
- </el-table>
|
|
|
- <br>
|
|
|
- <div style="margin-top: 15px;">
|
|
|
- <el-input
|
|
|
- v-model="albumForm.albumName"
|
|
|
- placeholder="请输入标题(最多可输入20个字)"
|
|
|
- maxlength="20"
|
|
|
- clearable
|
|
|
- >
|
|
|
- <el-button slot="append" icon="el-icon-plus" @click="onCreateAlbum">新建收藏夹</el-button>
|
|
|
- </el-input>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
+ <el-dialog append-to-body :visible.sync="showPlaylistDialog" title="保存到收藏夹" width="400px" center>
|
|
|
+ <el-table :data="playlist" highlight-current-row @current-change="handleCurrentRow">
|
|
|
+ <el-table-column type="index" width="50" />
|
|
|
+ <el-table-column prop="albumName" label="收藏夹名称" />
|
|
|
+ <el-table-column prop="total" label="内容数" width="80" />
|
|
|
+ </el-table>
|
|
|
+ <div class="new-album-input">
|
|
|
+ <el-input v-model="albumForm.albumName" placeholder="新建收藏夹..." size="medium">
|
|
|
+ <el-button slot="append" icon="el-icon-plus" @click="onCreateAlbum">创建</el-button>
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ <span slot="footer">
|
|
|
+ <el-button @click="showPlaylistDialog = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="addToPlaylist">确定收藏</el-button>
|
|
|
+ </span>
|
|
|
</el-dialog>
|
|
|
- <!-- 视频报错对话框 -->
|
|
|
- <el-dialog
|
|
|
- append-to-body
|
|
|
- :visible.sync="showErrorReportDialog"
|
|
|
- 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 append-to-body :visible.sync="showErrorReportDialog" title="视频报错" width="400px">
|
|
|
+ <el-form :model="errorReportForm" label-position="top">
|
|
|
+ <el-form-item label="请选择错误类型">
|
|
|
+ <el-select v-model="errorReportForm.errorCode" placeholder="请选择" style="width: 100%">
|
|
|
+ <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>
|
|
|
+ <span slot="footer">
|
|
|
+ <el-button @click="showErrorReportDialog = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="submitErrorReport">提交反馈</el-button>
|
|
|
+ </span>
|
|
|
</el-dialog>
|
|
|
- <!-- 视频分享对话框 -->
|
|
|
- <el-dialog
|
|
|
- append-to-body
|
|
|
- :visible.sync="showShareVideoDialog"
|
|
|
- center
|
|
|
- >
|
|
|
- <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px; padding-top: 5px">
|
|
|
- <el-col :md="12">
|
|
|
- <el-row>
|
|
|
- <div class="imgs">
|
|
|
- <el-image
|
|
|
- lazy
|
|
|
- fit="cover"
|
|
|
- class="coverImg"
|
|
|
- :src="video.coverUrl"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </el-row>
|
|
|
- <el-row>
|
|
|
- <el-button style="float: right; padding: 3px 0" type="text" @click="submitShareVideo">获取视频分享链接</el-button>
|
|
|
- </el-row>
|
|
|
- </el-col>
|
|
|
- <el-col :md="12" />
|
|
|
- </el-row>
|
|
|
- <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px; padding-top: 5px" />
|
|
|
+
|
|
|
+ <el-dialog append-to-body :visible.sync="showShareVideoDialog" title="分享视频" width="500px">
|
|
|
+ <div class="share-preview">
|
|
|
+ <el-image lazy fit="cover" class="share-cover" :src="video.coverUrl" />
|
|
|
+ <h4 v-html="video.title"></h4>
|
|
|
+ </div>
|
|
|
+ <span slot="footer">
|
|
|
+ <el-button type="primary" icon="el-icon-document-copy" @click="submitShareVideo">复制分享链接</el-button>
|
|
|
+ </span>
|
|
|
</el-dialog>
|
|
|
- <!-- 视频编辑对话框 -->
|
|
|
+
|
|
|
<edit-video-card :video="video" :create-dialog="showEditDialog" @closeDialog="closeHandle" />
|
|
|
</el-row>
|
|
|
</el-row>
|
|
|
- <el-row v-else>
|
|
|
+ <el-row v-else class="denied-container">
|
|
|
<permission-denied-card :text-object="textObject" />
|
|
|
</el-row>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import PermissionDeniedCard from '@/components/card/PermissionDeniedCard'
|
|
|
-import SideVideoCard from 'components/card/SideVideoCard'
|
|
|
-import UserAvatarCard from '@/components/card/UserAvatarCard'
|
|
|
-import EditVideoCard from '@/components/card/EditVideoCard'
|
|
|
-import comment from '@/components/comment'
|
|
|
-
|
|
|
-import { similarVideo, videoInfo, downloadVideo, getShortUrl, videoUrl } from '@/api/video'
|
|
|
+import { similarVideo, videoInfo, downloadVideo, getShortUrl } from '@/api/video'
|
|
|
import { videoErrorReport, videoErrorDelete } from '@/api/video_edit'
|
|
|
import { collectItem, createAlbum, getUserAlbumList } from '@/api/collect'
|
|
|
import { getUserInfo } from '@/api/user'
|
|
|
-import { publishComment, getComment } from '@/api/comment'
|
|
|
import { getAccessToken, getAuthedUser } from '@/utils/auth'
|
|
|
import { dislikeVideo } from '@/api/content'
|
|
|
-import flvjs from 'flv.js'
|
|
|
-import DPlayer from 'dplayer'
|
|
|
+
|
|
|
+// 组件导入
|
|
|
+import PermissionDeniedCard from '@/components/card/PermissionDeniedCard'
|
|
|
+import VideoPlayerCard from 'components/card/VideoPlayerCard'
|
|
|
+import SideVideoCard from 'components/card/SideVideoCard'
|
|
|
+import UserAvatarCard from '@/components/card/UserAvatarCard'
|
|
|
+import EditVideoCard from '@/components/card/EditVideoCard'
|
|
|
+import UserCommentCard from '@/components/card/UserCommentCard'
|
|
|
+import VideoOpsCard from 'components/card/VideoOpsCard'
|
|
|
|
|
|
export default {
|
|
|
name: 'VideoPage',
|
|
|
- components: { EditVideoCard, SideVideoCard, UserAvatarCard, PermissionDeniedCard, comment },
|
|
|
+ components: { EditVideoCard, SideVideoCard, UserAvatarCard, PermissionDeniedCard, VideoPlayerCard, UserCommentCard, VideoOpsCard },
|
|
|
data() {
|
|
|
return {
|
|
|
- // 屏幕宽度, 为了控制分页条的大小
|
|
|
screenWidth: document.body.clientWidth,
|
|
|
- currentPage: 1,
|
|
|
- pageSize: 20,
|
|
|
- totalSize: 0,
|
|
|
- dataList: [],
|
|
|
- // ********************************************************************/
|
|
|
- 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: -1,
|
|
|
- name: '芒果',
|
|
|
- avatar: '//picx.zhimg.com/v2-a2c89378a6332cbfed3e28b5ab84feb7.jpg',
|
|
|
- author: true
|
|
|
- },
|
|
|
- // 自定义组件中 comment 对象的字段名
|
|
|
- props: {
|
|
|
- id: 'commentId',
|
|
|
- content: 'content',
|
|
|
- imgSrc: 'imageUrl',
|
|
|
- children: 'children',
|
|
|
- likes: 'likes',
|
|
|
- liked: 'liked',
|
|
|
- reply: 'reply',
|
|
|
- createAt: 'createAt',
|
|
|
- total: 'total',
|
|
|
- user: 'user'
|
|
|
- },
|
|
|
- // ********************************************************************/
|
|
|
videoId: null,
|
|
|
video: null,
|
|
|
user: null,
|
|
|
similarVideos: [],
|
|
|
+ currentUser: { userId: -1, name: '游客', avatar: '', author: false },
|
|
|
isCollected: false,
|
|
|
showPlaylistDialog: false,
|
|
|
playlist: [],
|
|
|
showErrorReportDialog: false,
|
|
|
- errorReportForm: {
|
|
|
- videoId: null,
|
|
|
- errorCode: null
|
|
|
- },
|
|
|
+ errorReportForm: { videoId: null, errorCode: null },
|
|
|
permissionDenied: false,
|
|
|
- textObject: {
|
|
|
- content: '视频',
|
|
|
- route: '/video'
|
|
|
- },
|
|
|
+ textObject: { content: '视频', route: '/video' },
|
|
|
autoPlay: false,
|
|
|
- albumForm: {
|
|
|
- albumName: null
|
|
|
- },
|
|
|
+ albumForm: { albumName: null },
|
|
|
currentRow: null,
|
|
|
showShareVideoDialog: false,
|
|
|
showEditDialog: false,
|
|
|
showEdit: true,
|
|
|
- // ****************************************************************************************************************
|
|
|
- flvjs,
|
|
|
- DPlayer,
|
|
|
- danmaku: {
|
|
|
- api: process.env.VUE_APP_SERVER_URL + '/api/comment/danmaku/'
|
|
|
- },
|
|
|
userToken: null,
|
|
|
sendEvent: true,
|
|
|
- intervalEvent: null,
|
|
|
- // ****************************************************************************************************************
|
|
|
- wsUrl: null,
|
|
|
- realtimeViewCount: 0,
|
|
|
- wsClient: null,
|
|
|
- wsConnectStatus: false,
|
|
|
- wsReconnectLock: false
|
|
|
+ realtimeViewCount: 0
|
|
|
}
|
|
|
},
|
|
|
watch: {
|
|
|
- // 地址栏 url 发生变化时重新加载本页面
|
|
|
- $route() {
|
|
|
- this.$router.go()
|
|
|
- }
|
|
|
+ '$route'() { this.$router.go() }
|
|
|
},
|
|
|
created() {
|
|
|
this.userToken = getAccessToken()
|
|
|
- this.danmaku.token = this.userToken
|
|
|
-
|
|
|
const loginUser = getAuthedUser()
|
|
|
- if (loginUser != null) {
|
|
|
- this.currentUser = {
|
|
|
- userId: loginUser.userId,
|
|
|
- name: loginUser.screenName,
|
|
|
- avatar: loginUser.avatarUrl,
|
|
|
- author: true
|
|
|
- }
|
|
|
+ if (loginUser) {
|
|
|
+ this.currentUser = { userId: loginUser.userId, name: loginUser.screenName, avatar: loginUser.avatarUrl, author: true }
|
|
|
}
|
|
|
-
|
|
|
this.videoId = this.$route.params.id
|
|
|
this.getVideoInfo(this.videoId)
|
|
|
this.getSimilarVideos(this.videoId)
|
|
|
- this.getCommentWrapper(this.currentPage)
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- const header = this.$refs.header
|
|
|
- if (header !== undefined && header !== null) {
|
|
|
- this.wrapStyle = `height: calc(100vh - ${header.clientHeight + 20}px)`
|
|
|
- }
|
|
|
},
|
|
|
methods: {
|
|
|
- handleCurrentRow(val) {
|
|
|
- this.currentRow = val
|
|
|
- this.$message.info('选中 ' + this.currentRow.albumName)
|
|
|
- },
|
|
|
- // 用户点击收藏
|
|
|
+ handleCurrentRow(val) { this.currentRow = val },
|
|
|
collection(video) {
|
|
|
- if (video.collected) {
|
|
|
- this.$message.info('取消收藏')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
+ if (video.collected) return this.$message.info('取消收藏')
|
|
|
this.showPlaylistDialog = true
|
|
|
- getUserAlbumList(1).then(resp => {
|
|
|
- if (resp.code === 0) {
|
|
|
- this.playlist = resp.data.list
|
|
|
- }
|
|
|
- })
|
|
|
+ getUserAlbumList(1).then(resp => { if (resp.code === 0) this.playlist = resp.data.list })
|
|
|
},
|
|
|
addToPlaylist() {
|
|
|
- if (this.currentRow === null) {
|
|
|
- this.$message.info('请选择收藏夹')
|
|
|
- return
|
|
|
- }
|
|
|
- const jsonData = {}
|
|
|
- jsonData.albumId = this.currentRow.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
|
|
|
- })
|
|
|
- }
|
|
|
- }).catch(error => {
|
|
|
- this.$message.error(error)
|
|
|
- }).finally(() => {
|
|
|
+ if (!this.currentRow) return this.$message.info('请选择收藏夹')
|
|
|
+ collectItem({ albumId: this.currentRow.albumId, postId: this.videoId, action: 1 }).then(resp => {
|
|
|
+ if (resp.code === 0) this.$notify.success({ title: '视频已收藏' })
|
|
|
this.showPlaylistDialog = false
|
|
|
})
|
|
|
},
|
|
|
- // ****************************************************************************************************************
|
|
|
- handleCurrentChange(currentPage) {
|
|
|
- this.currentPage = currentPage
|
|
|
- this.getCommentWrapper(currentPage)
|
|
|
- // 回到顶部
|
|
|
- scrollTo(0, 0)
|
|
|
- },
|
|
|
- getCommentWrapper(pageNumber) {
|
|
|
- getComment(this.videoId, pageNumber).then(resp => {
|
|
|
- if (resp.code === 0) {
|
|
|
- const respData = resp.data
|
|
|
- this.dataList = respData.list
|
|
|
- this.totalSize = respData.totalSize
|
|
|
- } else {
|
|
|
- this.$notify({
|
|
|
- title: '提示',
|
|
|
- message: resp.msg,
|
|
|
- type: 'error',
|
|
|
- duration: 3000
|
|
|
- })
|
|
|
- }
|
|
|
- }).catch(error => {
|
|
|
- this.$notify({
|
|
|
- title: '提示',
|
|
|
- message: error.message,
|
|
|
- type: 'warning',
|
|
|
- duration: 3000
|
|
|
- })
|
|
|
- })
|
|
|
- },
|
|
|
- // ****************************************************************************************************************
|
|
|
- // 获取视频的详细信息
|
|
|
getVideoInfo(videoId) {
|
|
|
videoInfo(videoId).then(resp => {
|
|
|
if (resp.code === 0) {
|
|
|
this.video = resp.data
|
|
|
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
|
|
|
- })
|
|
|
- }
|
|
|
- })
|
|
|
- this.getVideoUrl(videoId)
|
|
|
+ this.loadUserInfo(resp.data.userId)
|
|
|
} 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
|
|
|
- } else {
|
|
|
- this.$notify.error({
|
|
|
- message: '推荐视频数据获取失败',
|
|
|
- type: 'warning',
|
|
|
- duration: 3000
|
|
|
- })
|
|
|
- }
|
|
|
- }).catch(error => {
|
|
|
- this.$notify.error({
|
|
|
- message: error.message,
|
|
|
- type: 'warning',
|
|
|
- duration: 3000
|
|
|
- })
|
|
|
- })
|
|
|
+ loadUserInfo(userId) {
|
|
|
+ getUserInfo(userId).then(resp => { if (resp.code === 0) this.user = resp.data })
|
|
|
},
|
|
|
- // 换一换
|
|
|
- refreshSimilar() {
|
|
|
- console.log('刷新相关推荐')
|
|
|
- },
|
|
|
- likeVideo(video) {
|
|
|
- const videoId = video.videoId
|
|
|
- this.$message.info('喜欢 ' + videoId)
|
|
|
+ getSimilarVideos(videoId) {
|
|
|
+ similarVideo(videoId).then(resp => { if (resp.code === 0) this.similarVideos = resp.data })
|
|
|
},
|
|
|
+ likeVideo(video) { this.$message.info('喜欢 ' + video.videoId) },
|
|
|
dislikeVideoWrapper(video) {
|
|
|
- const payload = {
|
|
|
- videoId: video.videoId
|
|
|
- }
|
|
|
- dislikeVideo(payload).then(resp => {
|
|
|
- if (resp.code === 0) {
|
|
|
- this.$message.info('数据已提交')
|
|
|
- }
|
|
|
- })
|
|
|
+ dislikeVideo({ videoId: video.videoId }).then(resp => { if (resp.code === 0) this.$message.info('数据已提交') })
|
|
|
},
|
|
|
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
|
|
|
- })
|
|
|
+ if (resp.code === 0) window.open(resp.data.url, '_blank')
|
|
|
})
|
|
|
},
|
|
|
onCreateAlbum() {
|
|
|
- createAlbum(this.albumForm).then(resp => {
|
|
|
- if (resp.code === 0) {
|
|
|
- this.playlist.push(resp.data)
|
|
|
- }
|
|
|
- })
|
|
|
+ createAlbum(this.albumForm).then(resp => { if (resp.code === 0) this.playlist.push(resp.data) })
|
|
|
this.albumForm.albumName = null
|
|
|
},
|
|
|
deleteVideo(video) {
|
|
|
- this.$confirm('确定要删除 ' + video.title + '?', '提示', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning',
|
|
|
- customClass: 'msgbox'
|
|
|
- }).then(() => {
|
|
|
- const videoId = video.videoId
|
|
|
- const errorReportForm = {
|
|
|
- videoId: videoId,
|
|
|
- errorCode: 4
|
|
|
- }
|
|
|
-
|
|
|
- videoErrorDelete(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
|
|
|
- })
|
|
|
- })
|
|
|
- }).catch(() => {
|
|
|
- this.$message({
|
|
|
- type: 'info',
|
|
|
- message: '已取消'
|
|
|
+ this.$confirm('确定要删除 ' + video.title + '?', '提示', { type: 'warning' }).then(() => {
|
|
|
+ videoErrorDelete({ videoId: video.videoId, errorCode: 4 }).then(resp => {
|
|
|
+ if (resp.code === 0) this.$notify.warning({ title: '提示', message: '视频错误已提交' })
|
|
|
})
|
|
|
})
|
|
|
},
|
|
|
- displayErrorReportDialog() {
|
|
|
- this.errorReportForm.videoId = this.video.videoId
|
|
|
- this.showErrorReportDialog = true
|
|
|
- },
|
|
|
+ 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
|
|
|
- })
|
|
|
+ if (resp.code === 0) this.$notify.warning({ title: '提示', message: '视频错误已提交' })
|
|
|
+ this.showErrorReportDialog = false
|
|
|
})
|
|
|
},
|
|
|
- displayShareVideoDialog() {
|
|
|
- this.showShareVideoDialog = true
|
|
|
- },
|
|
|
- displayEditDialog() {
|
|
|
- this.showEditDialog = true
|
|
|
- },
|
|
|
- closeHandle() {
|
|
|
- // 控制取消和X按钮,关闭弹窗
|
|
|
- this.showEditDialog = false
|
|
|
- },
|
|
|
+ displayShareVideoDialog() { this.showShareVideoDialog = true },
|
|
|
+ displayEditDialog() { this.showEditDialog = true },
|
|
|
+ closeHandle() { this.showEditDialog = false },
|
|
|
submitShareVideo() {
|
|
|
- this.showShareVideoDialog = false
|
|
|
getShortUrl(this.video.videoId).then(resp => {
|
|
|
if (resp.code === 0) {
|
|
|
const content = window.location.origin + resp.data
|
|
|
- if (window.clipboardData) {
|
|
|
- window.clipboardData.setData('text', content)
|
|
|
- } else {
|
|
|
- (function() {
|
|
|
- document.oncopy = function(e) {
|
|
|
- e.clipboardData.setData('text', content)
|
|
|
- e.preventDefault()
|
|
|
- document.oncopy = null
|
|
|
- }
|
|
|
- })(content)
|
|
|
- document.execCommand('Copy')
|
|
|
- }
|
|
|
+ const input = document.createElement('input'); input.value = content; document.body.appendChild(input);
|
|
|
+ input.select(); document.execCommand('Copy'); document.body.removeChild(input);
|
|
|
this.$message.info('已成功复制到剪贴板')
|
|
|
- } 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)
|
|
|
- },
|
|
|
- // ****************************************************************************************************************
|
|
|
- getVideoUrl(videoId) {
|
|
|
- videoUrl(videoId).then(res => {
|
|
|
- if (res.code === 0) {
|
|
|
- if (this.userToken != null && this.sendEvent) {
|
|
|
- // this.wsUrl = 'wss:' + process.env.VUE_APP_SERVER_URL + '/ws/media?userToken=' + this.userToken + '&videoId=' + videoId
|
|
|
- this.wsUrl = this.getUrl(videoId)
|
|
|
- this.initWebSocket()
|
|
|
- }
|
|
|
-
|
|
|
- const coverUrl = this.video.coverUrl
|
|
|
- const loginUserId = this.currentUser.userId
|
|
|
- const urlType = res.data.type
|
|
|
- if (urlType === 'mp4') {
|
|
|
- const urls = res.data.urls
|
|
|
- for (const url of urls) {
|
|
|
- url.type = 'normal'
|
|
|
- }
|
|
|
- this.initMp4Player(loginUserId, videoId, coverUrl, urls, res.data.currentTime)
|
|
|
- } else if (urlType === 'flv') {
|
|
|
- const urls = res.data.urls
|
|
|
- this.initFlvPlayer(loginUserId, videoId, coverUrl, urls, res.data.currentTime)
|
|
|
- } 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
|
|
|
- })
|
|
|
- })
|
|
|
- },
|
|
|
- getUrl(videoId) {
|
|
|
- const protocol = location.protocol
|
|
|
- const hostname = location.hostname
|
|
|
- const port = location.port
|
|
|
- let prefix
|
|
|
- if (protocol === 'https:') {
|
|
|
- if (port === '' || port === 443) {
|
|
|
- prefix = 'wss://' + hostname
|
|
|
- } else {
|
|
|
- prefix = 'wss://' + hostname + ':' + port
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (port === '' || port === 80) {
|
|
|
- prefix = 'ws://' + hostname
|
|
|
- } else {
|
|
|
- prefix = 'ws://' + hostname + ':' + port
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- var wsUrl = prefix + '/ws/media?userToken=' + this.userToken + '&videoId=' + videoId
|
|
|
- return wsUrl
|
|
|
- },
|
|
|
- danmakuConfig() {
|
|
|
- // TODO 获取弹幕配置,将 videoUrl 作为本函数的回调
|
|
|
- },
|
|
|
- initMp4Player(userId, videoId, coverUrl, urls, pos) {
|
|
|
- const player = new DPlayer({
|
|
|
- container: document.querySelector('#dplayer'),
|
|
|
- lang: 'zh-cn',
|
|
|
- screenshot: true,
|
|
|
- autoplay: false,
|
|
|
- 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.userToken,
|
|
|
- bottom: '15%',
|
|
|
- unlimited: true
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- // 设置音量
|
|
|
- // player.volume(0.1, true, false)
|
|
|
- // 跳转到上次看到的位置
|
|
|
- player.seek(pos)
|
|
|
-
|
|
|
- var ended = false
|
|
|
- /* 事件绑定 */
|
|
|
- const that = this
|
|
|
- player.on('play', function() {
|
|
|
- if (that.sendEvent) {
|
|
|
- clearInterval(that.intervalEvent)
|
|
|
- that.intervalEvent = setInterval(() => {
|
|
|
- if (!ended) {
|
|
|
- const jsonData = {}
|
|
|
- jsonData.type = 'progress'
|
|
|
- jsonData.direction = 'c2s'
|
|
|
- jsonData.data = {
|
|
|
- mediaId: videoId,
|
|
|
- mediaType: 1,
|
|
|
- currentTime: player.video.currentTime,
|
|
|
- ended: ended
|
|
|
- }
|
|
|
- that.sendJsonMessage(jsonData)
|
|
|
- }
|
|
|
- }, 5000)
|
|
|
- }
|
|
|
- })
|
|
|
- player.on('ended', () => {
|
|
|
- clearInterval(that.intervalEvent)
|
|
|
- ended = true
|
|
|
- if (that.sendEvent) {
|
|
|
- const jsonData = {}
|
|
|
- jsonData.type = 'progress'
|
|
|
- jsonData.direction = 'c2s'
|
|
|
- jsonData.data = {
|
|
|
- mediaId: videoId,
|
|
|
- mediaType: 1,
|
|
|
- currentTime: player.video.currentTime,
|
|
|
- ended: ended
|
|
|
- }
|
|
|
- that.sendJsonMessage(jsonData)
|
|
|
- }
|
|
|
- })
|
|
|
- player.on('volumechange', () => {
|
|
|
- console.log('声音改变')
|
|
|
- })
|
|
|
- },
|
|
|
- initFlvPlayer(userId, videoId, coverUrl, urls, pos) {
|
|
|
- const player = new DPlayer({
|
|
|
- container: document.getElementById('dplayer'),
|
|
|
- lang: 'zh-cn',
|
|
|
- screenshot: true,
|
|
|
- autoplay: false,
|
|
|
- volume: 0.1,
|
|
|
- mutex: true,
|
|
|
- video: {
|
|
|
- pic: coverUrl,
|
|
|
- defaultQuality: 0,
|
|
|
- quality: urls,
|
|
|
- hotkey: true,
|
|
|
- type: 'customFlv',
|
|
|
- customType: {
|
|
|
- customFlv: function(video, player) {
|
|
|
- const flvPlayer = flvjs.createPlayer({
|
|
|
- type: 'flv',
|
|
|
- url: video.src
|
|
|
- })
|
|
|
- flvPlayer.attachMediaElement(video)
|
|
|
- flvPlayer.load()
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
+ this.showShareVideoDialog = false
|
|
|
})
|
|
|
-
|
|
|
- // 跳转到上次看到的位置
|
|
|
- player.seek(pos)
|
|
|
- /* 事件绑定 */
|
|
|
- player.on('ended', () => {
|
|
|
- })
|
|
|
- player.on('volumechange', () => {
|
|
|
- console.log('声音改变')
|
|
|
- })
|
|
|
- },
|
|
|
- // ****************************************************************************************************************
|
|
|
- // websocket
|
|
|
- initWebSocket() {
|
|
|
- if ('WebSocket' in window) {
|
|
|
- this.wsClient = new WebSocket(this.wsUrl)
|
|
|
- const that = this
|
|
|
- this.wsClient.onopen = function() {
|
|
|
- that.setOnline()
|
|
|
- }
|
|
|
- this.wsClient.onclose = function() {
|
|
|
- that.setOffline()
|
|
|
- that.reconnect()
|
|
|
- }
|
|
|
- this.wsClient.onerror = function() {
|
|
|
- that.setOffline()
|
|
|
- console.log('websocket connection error...')
|
|
|
- that.reconnect()
|
|
|
- }
|
|
|
- this.wsClient.onmessage = function(evt) {
|
|
|
- that.processMessage(evt.data)
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 浏览器不支持 WebSocket
|
|
|
- this.$message.error('您的浏览器不支持 WebSocket!')
|
|
|
- }
|
|
|
- },
|
|
|
- setOnline() {
|
|
|
- this.wsConnectStatus = true
|
|
|
- },
|
|
|
- setOffline() {
|
|
|
- this.wsConnectStatus = false
|
|
|
- this.realtimeViewCount = 0
|
|
|
- },
|
|
|
- reconnect() {
|
|
|
- if (this.wsReconnectLock) return
|
|
|
- this.wsReconnectLock = true
|
|
|
- const that = this
|
|
|
- setTimeout(function() {
|
|
|
- console.log('websocket reconnecting...')
|
|
|
- that.initWebSocket()
|
|
|
- that.wsReconnectLock = false
|
|
|
- }, 5000)
|
|
|
- },
|
|
|
- sendJsonMessage(message) {
|
|
|
- const jsonStr = JSON.stringify(message)
|
|
|
- this.wsClient.send(jsonStr)
|
|
|
- },
|
|
|
- processMessage(message) {
|
|
|
- const jsonMessage = JSON.parse(message)
|
|
|
- this.realtimeViewCount = jsonMessage.viewCount
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-/*处于手机屏幕时*/
|
|
|
-@media screen and (max-width: 768px) {
|
|
|
- .movie-list {
|
|
|
- padding-top: 8px;
|
|
|
- padding-left: 0.5%;
|
|
|
- padding-right: 0.5%;
|
|
|
- }
|
|
|
- /* 或者使用这种更具体的选择器 */
|
|
|
- .el-dialog__wrapper .maintenance-dialog {
|
|
|
- width: 100% !important;
|
|
|
- margin-top: 5vh !important;
|
|
|
- }
|
|
|
-
|
|
|
- /* 表单布局优化 */
|
|
|
- .maintenance-dialog .el-form-item {
|
|
|
- margin-bottom: 15px;
|
|
|
- }
|
|
|
+.video-page-container { padding: 20px; background-color: #f4f4f5; min-height: 100vh; }
|
|
|
+.shadow-box { box-shadow: 0 2px 12px 0 rgba(0,0,0,0.05) !important; border: none !important; border-radius: 8px !important; background: #fff; }
|
|
|
+.player-section { background: #1a1a1a; padding: 20px; margin-bottom: 20px; }
|
|
|
+.video-header { margin-bottom: 15px; }
|
|
|
+.video-title { color: #fff; font-size: 20px; margin: 0 0 10px 0; font-weight: 600; }
|
|
|
+.video-meta { display: flex; justify-content: space-between; align-items: center; color: #999; font-size: 13px; }
|
|
|
+.meta-item { margin-right: 20px; }
|
|
|
+.video-content { background: #000; border-radius: 4px; overflow: hidden; margin-bottom: 15px; }
|
|
|
+.bili-link { color: inherit; text-decoration: none; }
|
|
|
+.info-card { margin-bottom: 20px; padding: 10px; }
|
|
|
+.video-description { font-size: 14px; color: #606266; line-height: 1.6; white-space: pre-wrap; }
|
|
|
+.video-tags { margin-top: 20px; padding-top: 15px; border-top: 1px solid #ebeef5; }
|
|
|
+.video-tag-item { margin-right: 10px; margin-bottom: 8px; border: none; background: #f0f2f5; }
|
|
|
+.video-tag-item a { text-decoration: none; color: #409EFF; }
|
|
|
+.side-container { position: sticky; top: 20px; }
|
|
|
+.recommend-header { display: flex; justify-content: space-between; align-items: center; }
|
|
|
+.recommend-header .title { font-weight: 600; font-size: 16px; }
|
|
|
+.auto-play { font-size: 12px; color: #909399; display: flex; align-items: center; }
|
|
|
+.auto-play span { margin-right: 8px; }
|
|
|
+.side-card-wrapper { margin-bottom: 12px; transition: transform 0.2s; }
|
|
|
+.side-card-wrapper:hover { transform: translateX(5px); }
|
|
|
+.new-album-input { margin-top: 20px; }
|
|
|
+.share-preview { text-align: center; }
|
|
|
+.share-cover { width: 100%; height: 200px; border-radius: 8px; margin-bottom: 15px; }
|
|
|
+.mb-20 { margin-bottom: 20px; }
|
|
|
|
|
|
- .maintenance-dialog .el-form-item__label {
|
|
|
- float: none !important;
|
|
|
- display: block !important;
|
|
|
- text-align: left !important;
|
|
|
- padding: 0 0 8px !important;
|
|
|
- width: 100% !important;
|
|
|
- }
|
|
|
-
|
|
|
- .maintenance-dialog .el-form-item__content {
|
|
|
- margin-left: 0 !important;
|
|
|
- }
|
|
|
-
|
|
|
- /* 确保所有输入控件宽度100% */
|
|
|
- .maintenance-dialog .el-input,
|
|
|
- .maintenance-dialog .el-select,
|
|
|
- .maintenance-dialog .el-date-picker,
|
|
|
- .maintenance-dialog .el-input-number {
|
|
|
- width: 100% !important;
|
|
|
- }
|
|
|
-
|
|
|
- /* 调整按钮组间距 */
|
|
|
- .maintenance-dialog .dialog-footer {
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
-
|
|
|
- .maintenance-dialog .dialog-footer .el-button {
|
|
|
- margin: 0 5px;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.movie-list {
|
|
|
- padding-top: 5px;
|
|
|
- padding-bottom: 5px;
|
|
|
- padding-left: 5px;
|
|
|
- padding-right: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.clearfix:before,
|
|
|
-.clearfix:after {
|
|
|
- display: table;
|
|
|
- content: "";
|
|
|
-}
|
|
|
-
|
|
|
-.clearfix:after {
|
|
|
- clear: both;
|
|
|
-}
|
|
|
-
|
|
|
-.tag{
|
|
|
- padding-top: 1px;
|
|
|
- padding-bottom: 1px;
|
|
|
- margin-left: 3px;
|
|
|
- margin-right: 3px;
|
|
|
-}
|
|
|
-
|
|
|
-.imgs {
|
|
|
- position: relative;
|
|
|
-}
|
|
|
-
|
|
|
-.coverImg {
|
|
|
- width: 100%;
|
|
|
- height: 175px;
|
|
|
- display: block;
|
|
|
+@media screen and (max-width: 768px) {
|
|
|
+ .video-page-container { padding: 10px; }
|
|
|
+ .video-title { font-size: 16px; }
|
|
|
+ .meta-right { display: none; }
|
|
|
}
|
|
|
</style>
|