video.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. <template>
  2. <div v-if="videoData !== null">
  3. <v-container>
  4. <v-col>
  5. <v-row>
  6. <v-col>
  7. <h3 v-text="videoData.title" />
  8. </v-col>
  9. </v-row>
  10. <v-row>
  11. <v-col style="color: #999;font-size: 12px;padding-top: 0px;">
  12. <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
  13. <span v-text="videoData.viewCount" /> 次观看 <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
  14. <span v-text="TimeUtil.renderTime(videoData.pubDate)" />
  15. </v-col>
  16. </v-row>
  17. </v-col>
  18. </v-container>
  19. <v-container>
  20. <v-row>
  21. <v-col>
  22. <VideoPlayer v-if="vidProp !== null" :video-prop="vidProp" />
  23. </v-col>
  24. <v-col>
  25. <v-card
  26. light
  27. >
  28. <v-card-title>
  29. <span>合集 </span>
  30. <v-switch
  31. v-model="switch1"
  32. :label="`自动播放`"
  33. />
  34. </v-card-title>
  35. <v-virtual-scroll
  36. :bench="benched"
  37. :items="videoCollection"
  38. height="300"
  39. item-height="64"
  40. >
  41. <template v-slot:default="{ item }">
  42. <v-list-item :key="item.videoId">
  43. <v-list-item-content>
  44. <v-list-item-title>
  45. <p class="text-over" style="font-size: 15px; margin-bottom: 0px;color: black;">
  46. <router-link :to="`/video/${item.videoId}`" style="color: black;"> {{ item.title }} </router-link>
  47. </p>
  48. </v-list-item-title>
  49. </v-list-item-content>
  50. </v-list-item>
  51. <v-divider />
  52. </template>
  53. </v-virtual-scroll>
  54. </v-card>
  55. </v-col>
  56. </v-row>
  57. </v-container>
  58. <v-container fill-height style="padding-top: 0px;">
  59. <v-row v-resize="onResize" no-gutters>
  60. <v-col :cols="colsWidth">
  61. <v-row>
  62. <v-col cols="2">
  63. <v-btn icon @click="likeVideo">
  64. <v-icon>mdi-thumb-up</v-icon>
  65. <span>点赞(10000)</span>
  66. </v-btn>
  67. </v-col>
  68. <v-col cols="2">
  69. <v-btn icon @click="collectVideoWrapper">
  70. <v-icon>mdi-bookmark</v-icon>
  71. <span>收藏(10000)</span>
  72. </v-btn>
  73. </v-col>
  74. <v-col cols="2">
  75. <v-btn icon @click="openRepostDialog">
  76. <v-icon>mdi-repeat</v-icon>
  77. <span>转发(10000)</span>
  78. </v-btn>
  79. <v-dialog
  80. v-model="showRepostDialog"
  81. persistent
  82. max-width="600px"
  83. >
  84. <v-card>
  85. <v-card-text>
  86. <span>https://bili.reghao.cn/video/lajfda</span>
  87. </v-card-text>
  88. <v-card-actions>
  89. <v-spacer />
  90. <v-btn
  91. color="blue darken-1"
  92. text
  93. @click="showRepostDialog = false"
  94. >
  95. 关闭
  96. </v-btn>
  97. </v-card-actions>
  98. </v-card>
  99. </v-dialog>
  100. </v-col>
  101. <v-col cols="2">
  102. <v-btn icon @click="openSuggestDialog">
  103. <v-icon>mdi-thumb-up</v-icon>
  104. <span>反馈</span>
  105. </v-btn>
  106. <v-dialog
  107. v-model="showDialog"
  108. persistent
  109. max-width="600px"
  110. >
  111. <v-card>
  112. <v-card-title>
  113. <span class="text-h5">问题或建议</span>
  114. </v-card-title>
  115. <v-card-text>
  116. <v-container>
  117. <v-row>
  118. <v-col
  119. cols="12"
  120. sm="6"
  121. >
  122. <v-select
  123. :items="['视频封面', '视频播放', '视频内容']"
  124. label="问题分类"
  125. required
  126. />
  127. </v-col>
  128. <v-col
  129. cols="24"
  130. sm="6"
  131. md="4"
  132. >
  133. <v-text-field
  134. label="问题或建议"
  135. required
  136. />
  137. </v-col>
  138. </v-row>
  139. </v-container>
  140. </v-card-text>
  141. <v-card-actions>
  142. <v-spacer />
  143. <v-btn
  144. color="blue darken-1"
  145. text
  146. @click="showDialog = false"
  147. >
  148. 关闭
  149. </v-btn>
  150. <v-btn
  151. color="blue darken-1"
  152. text
  153. @click="submitVideoErr"
  154. >
  155. 提交
  156. </v-btn>
  157. </v-card-actions>
  158. </v-card>
  159. </v-dialog>
  160. </v-col>
  161. <v-col cols="2">
  162. <v-btn icon @click="openEditDialog">
  163. <v-icon>mdi-thumb-up</v-icon>
  164. <span>编辑</span>
  165. </v-btn>
  166. <v-dialog
  167. v-model="showEditDialog"
  168. persistent
  169. max-width="600px"
  170. >
  171. <v-form
  172. ref="form"
  173. v-model="editVideo"
  174. lazy-validation
  175. >
  176. <v-text-field
  177. v-model="videoId"
  178. label="视频 ID"
  179. required
  180. />
  181. <v-text-field
  182. v-model="editVideo.pubDate"
  183. label="发布日期"
  184. required
  185. />
  186. <v-btn
  187. color="success"
  188. class="mr-4"
  189. @click="submitEdit"
  190. >
  191. 提交
  192. </v-btn>
  193. <v-btn
  194. color="error"
  195. class="mr-4"
  196. @click="resetEdit"
  197. >
  198. 重置
  199. </v-btn>
  200. <v-btn
  201. color="error"
  202. class="mr-4"
  203. @click="showEditDialog = false"
  204. >
  205. 取消
  206. </v-btn>
  207. </v-form>
  208. </v-dialog>
  209. </v-col>
  210. </v-row>
  211. <!--<v-row>
  212. <v-col style="color: #999;font-size: 12px;padding-top: 0px;">
  213. &lt;!&ndash;
  214. TODO 视频分类待完成
  215. <router-link v-if="videoData.childrenCategory.fatherId !== 0" :to="`/v/${videoData.fatherCategory.id}`" class="category-link">
  216. <span v-text="videoData.fatherCategory.name" />
  217. </router-link>
  218. /
  219. <router-link :to="`/v/${videoData.childrenCategory.id}`" class="category-link">
  220. <span v-text="videoData.childrenCategory.name" />
  221. </router-link>&ndash;&gt;
  222. <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
  223. </v-col>
  224. </v-row>-->
  225. <v-divider />
  226. <v-row>
  227. <v-col>
  228. <span v-text="videoData.description" />
  229. </v-col>
  230. </v-row>
  231. <v-divider />
  232. <v-row>
  233. <v-col>
  234. <span>{{ videoData.tags }}</span>
  235. <!-- <span v-for="item in videoData.tags" :key="item">
  236. <v-btn rounded small text color="primary" dark @click="jumpToTagPage(item)">{{ item }}</v-btn>
  237. </span>-->
  238. </v-col>
  239. </v-row>
  240. <v-divider />
  241. <v-row>
  242. <v-col cols="2" align-self="end">
  243. <router-link :to="`/u/${videoData.userId}`">
  244. <v-avatar size="48">
  245. <v-img :src="videoData.avatarUrl" />
  246. </v-avatar>
  247. </router-link>
  248. </v-col>
  249. <v-col>
  250. <router-link :to="`/u/${videoData.userId}`">
  251. <span v-text="videoData.username" />
  252. </router-link>
  253. <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
  254. <v-btn small outlined color="primary" @click="followingUser">
  255. <span>关注</span>
  256. <span v-html="'&nbsp;&nbsp;'" />
  257. <span v-text="videoData.followerCount" />
  258. </v-btn>
  259. </v-col>
  260. </v-row>
  261. </v-col>
  262. </v-row>
  263. <v-row>
  264. <v-col :cols="colsWidth">
  265. <CommentCard v-if="showComment === true" :video="videoData" />
  266. </v-col>
  267. <v-col>
  268. <v-row>
  269. <span>接下来播放: </span>
  270. <v-switch
  271. v-model="switch1"
  272. :label="`自动播放`"
  273. />
  274. </v-row>
  275. <v-row no-gutters>
  276. <v-col
  277. v-for="item in videoList"
  278. :key="item.videoId"
  279. >
  280. <item-card :video="item" />
  281. </v-col>
  282. </v-row>
  283. </v-col>
  284. </v-row>
  285. </v-container>
  286. <v-snackbar
  287. v-model="showMessage"
  288. :top="true"
  289. :timeout="1000"
  290. >
  291. {{ message }}
  292. <template v-slot:action="{ attrs }">
  293. <v-btn
  294. color="pink"
  295. text
  296. v-bind="attrs"
  297. @click="showMessage = false"
  298. >
  299. 关闭
  300. </v-btn>
  301. </template>
  302. </v-snackbar>
  303. </div>
  304. </template>
  305. <script>
  306. import { similarVideo, videoInfo, getDisplayedVideoList } from '@/api/media/video'
  307. import { collectVideo } from '@/api/media/collection'
  308. import ItemCard from '@/components/card/item-card.vue'
  309. import CommentCard from '@/components/card/comment-card.vue'
  310. import VideoPlayer from '@/components/player/player.vue'
  311. import TimeUtil from '@/utils/time-util.vue'
  312. export default {
  313. name: 'Video',
  314. components: {
  315. ItemCard,
  316. CommentCard,
  317. VideoPlayer
  318. },
  319. data() {
  320. return {
  321. videoList: [],
  322. videoCollection: [],
  323. score: 0,
  324. TimeUtil,
  325. videoId: '',
  326. videoData: null,
  327. windowSize: {
  328. },
  329. colsWidth: 8,
  330. showDialog: false,
  331. showRepostDialog: false,
  332. formData: {},
  333. collectionDialog: false,
  334. isCollected: '收藏',
  335. showEditDialog: false,
  336. editVideo: {
  337. videoId: null,
  338. pubDate: null
  339. },
  340. showComment: true,
  341. vidProp: null,
  342. benched: 0,
  343. switch1: true,
  344. showMessage: false,
  345. message: ''
  346. }
  347. },
  348. computed: {
  349. items() {
  350. return Array.from({ length: this.length }, (k, v) => v + 1)
  351. },
  352. length() {
  353. return 10
  354. }
  355. },
  356. created() {
  357. // 获取 url 上的 path 参数
  358. this.videoId = this.$route.params.id
  359. // 请求后端获取数据
  360. this.getVideoInfo(this.videoId)
  361. this.onResize()
  362. this.getSimilarVideos(this.videoId)
  363. this.getDisplayedVideoListWrapper()
  364. },
  365. mounted() {
  366. },
  367. methods: {
  368. // 控制页面大小
  369. onResize() {
  370. this.windowSize = { x: window.innerWidth, y: window.innerHeight }
  371. if (this.windowSize.x < 900) {
  372. this.colsWidth = 12
  373. } else {
  374. this.colsWidth = 8
  375. }
  376. },
  377. // 获取视频的详细信息
  378. getVideoInfo(videoId) {
  379. videoInfo(videoId)
  380. .then(res => {
  381. if (res.code === 0) {
  382. const vidData = res.data
  383. this.videoData = vidData
  384. document.title = vidData.title
  385. const vidProp = {}
  386. vidProp.videoId = vidData.videoId
  387. vidProp.coverUrl = vidData.coverUrl
  388. vidProp.scope = vidData.scope
  389. this.vidProp = vidProp
  390. } else {
  391. console.error(res.msg)
  392. }
  393. })
  394. .catch(error => {
  395. console.error(error.message)
  396. })
  397. },
  398. // 获取和当前视频类似的其他视频
  399. getSimilarVideos(videoId) {
  400. similarVideo(videoId)
  401. .then(res => {
  402. if (res.code === 0) {
  403. this.videoList = res.data
  404. } else {
  405. console.error(res.msg)
  406. }
  407. })
  408. .catch(error => {
  409. console.error(error.message)
  410. })
  411. },
  412. getDisplayedVideoListWrapper() {
  413. getDisplayedVideoList()
  414. .then(res => {
  415. if (res.code === 0) {
  416. this.videoCollection = res.data
  417. } else {
  418. console.error(res.msg)
  419. }
  420. })
  421. .catch(error => {
  422. console.error(error.message)
  423. })
  424. },
  425. followingUser() {
  426. console.log('关注 UP 主')
  427. },
  428. likeVideo() {
  429. console.log('点赞 ' + this.videoId)
  430. },
  431. collectVideoWrapper() {
  432. const obj = {}
  433. obj.videoId = this.videoId
  434. collectVideo(obj)
  435. .then(res => {
  436. if (res.code === 0) {
  437. this.showMessage = true
  438. this.message = '已收藏'
  439. } else {
  440. this.showMessage = true
  441. this.message = res.msg
  442. }
  443. })
  444. .catch(error => {
  445. console.error(error.message)
  446. })
  447. },
  448. jumpToTagPage(value) {
  449. console.log('跳转到标签页: ' + value)
  450. this.$router.push({
  451. path: '/tag/result',
  452. query: {
  453. tag: value,
  454. page: 1
  455. }
  456. })
  457. },
  458. openRepostDialog() {
  459. this.showRepostDialog = true
  460. console.log('获取一个 short url')
  461. },
  462. openSuggestDialog() {
  463. this.showDialog = true
  464. },
  465. openEditDialog() {
  466. this.showEditDialog = true
  467. },
  468. submitVideoErr() {
  469. this.showDialog = false
  470. console.log('提交视频错误')
  471. },
  472. submitEdit() {
  473. console.log('提交编辑信息')
  474. },
  475. resetEdit() {
  476. console.log('重置编辑信息')
  477. }
  478. }
  479. }
  480. </script>
  481. <style>
  482. </style>