VideoPage.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. <template>
  2. <el-row v-if="!permissionDenied">
  3. <el-row v-if="video !== null" class="movie-list">
  4. <el-col :md="15">
  5. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  6. <el-card class="box-card">
  7. <div slot="header" class="clearfix">
  8. <el-row>
  9. <h3 v-html="video.title" />
  10. </el-row>
  11. <el-row style="color: #999;font-size: 16px;padding-top: 0px;">
  12. <span><i class="el-icon-video-play">{{ video.view }}</i></span>
  13. <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
  14. <span><i class="el-icon-s-comment">{{ video.comment }}</i></span>
  15. <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
  16. <span><i class="el-icon-watch">{{ video.pubDate }}</i></span>
  17. <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
  18. <span v-if="videoId !== null && videoId.includes('BV')"><i class="el-icon-apple">
  19. <a target="_blank" :href="`https://bilibili.com/` + videoId">bili</a>
  20. </i></span>
  21. </el-row>
  22. </div>
  23. <div class="text item">
  24. <video-player :video-prop="video" />
  25. </div>
  26. </el-card>
  27. </el-row>
  28. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  29. <el-card class="box-card">
  30. <div slot="header" class="clearfix">
  31. <div class="tag">
  32. <el-button
  33. type="success"
  34. size="mini"
  35. icon="el-icon-plus"
  36. :disabled="isCollected"
  37. class="tag"
  38. @click="collection(video.videoId)"
  39. >
  40. <span>收藏 {{ video.favorite }}</span>
  41. </el-button>
  42. <el-button
  43. type="success"
  44. size="mini"
  45. icon="el-icon-thumb"
  46. :disabled="isCollected"
  47. class="tag"
  48. @click="collection(video)"
  49. >
  50. <span>喜欢 {{ video.thumbUp }}</span>
  51. </el-button>
  52. <el-button
  53. type="success"
  54. size="mini"
  55. icon="el-icon-share"
  56. :disabled="isCollected"
  57. class="tag"
  58. @click="getShareUrl(video.videoId)"
  59. >
  60. <span>分享 {{ video.share }}</span>
  61. </el-button>
  62. <el-button
  63. type="success"
  64. size="mini"
  65. icon="el-icon-download"
  66. class="tag"
  67. @click="getDownloadUrl(video.videoId)"
  68. >
  69. <span>下载</span>
  70. </el-button>
  71. <el-button
  72. type="danger"
  73. size="mini"
  74. icon="el-icon-delete"
  75. class="tag"
  76. @click="deleteVideo(video)"
  77. >
  78. <span>删除</span>
  79. </el-button>
  80. <el-button
  81. type="warning"
  82. size="mini"
  83. icon="el-icon-help"
  84. class="tag"
  85. @click="displayErrorReportDialog"
  86. >
  87. <span>报错</span>
  88. </el-button>
  89. </div>
  90. </div>
  91. <div class="text item">
  92. <!--视频描述行-->
  93. <span class="description" v-html="video.description" />
  94. <el-divider />
  95. <!--视频标签行-->
  96. <div>
  97. <el-tag
  98. v-for="(tag,index) in video.tags"
  99. :key="index"
  100. class="tag"
  101. size="medium"
  102. effect="plain"
  103. >
  104. <router-link style="text-decoration-line: none" target="_blank" :to="`/video/tag/` + tag">
  105. {{ tag }}
  106. </router-link>
  107. </el-tag>
  108. </div>
  109. </div>
  110. </el-card>
  111. </el-row>
  112. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  113. <el-card class="box-card">
  114. <div slot="header" class="clearfix">
  115. <el-row>
  116. <h3>视频评论</h3>
  117. </el-row>
  118. </div>
  119. <div class="text item">
  120. <div ref="comment" :style="wrapStyle" class="comment-wrap">
  121. <comment
  122. v-model="dataList"
  123. :user="currentUser"
  124. :props="props"
  125. :before-submit="submit"
  126. :before-like="like"
  127. :before-delete="deleteComment"
  128. :upload-img="uploadImg"
  129. />
  130. <el-pagination
  131. :small="screenWidth <= 768"
  132. hide-on-single-page
  133. layout="prev, pager, next"
  134. :page-size="pageSize"
  135. :current-page="currentPage"
  136. :total="totalSize"
  137. @current-change="handleCurrentChange"
  138. />
  139. </div>
  140. </div>
  141. </el-card>
  142. </el-row>
  143. </el-col>
  144. <el-col :md="9">
  145. <el-row>
  146. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  147. <user-avatar-card v-if="user !== null" :user-avatar="user" />
  148. </el-row>
  149. </el-row>
  150. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  151. <el-card class="box-card">
  152. <div slot="header" class="clearfix">
  153. <el-row>
  154. <h3>接下来播放</h3>
  155. </el-row>
  156. <el-row>
  157. <span>自动播放 <el-switch v-model="autoPlay" /></span>
  158. </el-row>
  159. </div>
  160. </el-card>
  161. </el-row>
  162. <el-row v-for="(item,index) in similarVideos" :key="index" style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  163. <side-video-card :video="item" />
  164. </el-row>
  165. </el-col>
  166. <!-- 添加到播放列表对话框 -->
  167. <el-dialog
  168. append-to-body
  169. :visible.sync="showPlaylistDialog"
  170. center
  171. >
  172. <el-card class="box-card">
  173. <div slot="header" class="clearfix">
  174. <span>添加到收藏夹</span>
  175. <el-button style="float: right; padding: 3px 0" type="text" @click="addToPlaylist">确定</el-button>
  176. </div>
  177. <div class="text item">
  178. <el-table
  179. ref="multipleTable"
  180. :show-header="false"
  181. :data="playlist"
  182. border
  183. style="width: 100%"
  184. @selection-change="handleSelectionChange"
  185. >
  186. <el-table-column type="selection" />
  187. <el-table-column
  188. prop="albumName"
  189. />
  190. <el-table-column
  191. prop="total"
  192. />
  193. <el-table-column
  194. prop="total"
  195. />
  196. </el-table>
  197. <br>
  198. <div style="margin-top: 15px;">
  199. <el-input
  200. v-model="albumForm.albumName"
  201. placeholder="请输入标题(最多可输入20个字)"
  202. maxlength="20"
  203. clearable
  204. >
  205. <el-button slot="append" icon="el-icon-plus" @click="onCreateAlbum">新建收藏夹</el-button>
  206. </el-input>
  207. </div>
  208. </div>
  209. </el-card>
  210. </el-dialog>
  211. <!-- 视频报错对话框 -->
  212. <el-dialog
  213. append-to-body
  214. :visible.sync="showErrorReportDialog"
  215. center
  216. >
  217. <el-card class="box-card">
  218. <div slot="header" class="clearfix">
  219. <span>视频报错</span>
  220. <el-button style="float: right; padding: 3px 0" type="text" @click="submitErrorReport">提交错误</el-button>
  221. </div>
  222. <div class="text item">
  223. <el-form ref="form" :model="errorReportForm" label-width="80px">
  224. <el-form-item label="错误类型">
  225. <el-select v-model="errorReportForm.errorCode" placeholder="选择视频错误类型">
  226. <el-option label="视频无封面" value="1" />
  227. <el-option label="视频无声音" value="2" />
  228. <el-option label="视频无画面" value="3" />
  229. <el-option label="视频无资源" value="4" />
  230. <el-option label="视频有广告" value="5" />
  231. </el-select>
  232. </el-form-item>
  233. </el-form>
  234. </div>
  235. </el-card>
  236. </el-dialog>
  237. </el-row>
  238. </el-row>
  239. <el-row v-else>
  240. <permission-denied-card :text-object="textObject" />
  241. </el-row>
  242. </template>
  243. <script>
  244. import PermissionDeniedCard from '@/components/card/PermissionDeniedCard'
  245. import VideoPlayer from 'components/VideoPlayer'
  246. import SideVideoCard from 'components/card/SideVideoCard'
  247. import UserAvatarCard from '@/components/card/UserAvatarCard'
  248. import comment from '@/components/comment'
  249. import { similarVideo, videoInfo, videoErrorReport, downloadVideo, getShortUrl, videoErrorDelete } from '@/api/video'
  250. import { collectItem, createAlbum, getUserPlaylist } from '@/api/collect'
  251. import { getUserInfo } from '@/api/user'
  252. import { publishComment, getComment } from '@/api/comment'
  253. import { getAuthedUser } from '@/utils/auth'
  254. export default {
  255. name: 'VideoPage',
  256. components: { SideVideoCard, VideoPlayer, UserAvatarCard, PermissionDeniedCard, comment },
  257. data() {
  258. return {
  259. // 屏幕宽度, 为了控制分页条的大小
  260. screenWidth: document.body.clientWidth,
  261. currentPage: 1,
  262. pageSize: 20,
  263. totalSize: 0,
  264. dataList: [],
  265. // ********************************************************************/
  266. wrapStyle: '',
  267. videoComments: [
  268. {
  269. commentId: 114511,
  270. content: 'this is comment content',
  271. imageUrl: '',
  272. children: [],
  273. likes: 0,
  274. liked: false,
  275. reply: null,
  276. createAt: 1700271326393,
  277. user: {
  278. userId: 1,
  279. name: '西瓜',
  280. avatar: ''
  281. }
  282. }
  283. ],
  284. currentUser: {
  285. userId: 9999,
  286. name: '芒果',
  287. avatar: '//picx.zhimg.com/v2-a2c89378a6332cbfed3e28b5ab84feb7.jpg',
  288. author: true
  289. },
  290. // 自定义组件中 comment 对象的字段名
  291. props: {
  292. id: 'commentId',
  293. content: 'content',
  294. imgSrc: 'imageUrl',
  295. children: 'children',
  296. likes: 'likes',
  297. liked: 'liked',
  298. reply: 'reply',
  299. createAt: 'createAt',
  300. total: 'total',
  301. user: 'user'
  302. },
  303. // ********************************************************************/
  304. videoId: null,
  305. video: null,
  306. user: null,
  307. similarVideos: [],
  308. isCollected: false,
  309. showPlaylistDialog: false,
  310. playlist: [],
  311. showErrorReportDialog: false,
  312. errorReportForm: {
  313. videoId: null,
  314. errorCode: null
  315. },
  316. permissionDenied: false,
  317. textObject: {
  318. content: '视频',
  319. route: '/video'
  320. },
  321. autoPlay: false,
  322. albumForm: {
  323. albumName: null
  324. },
  325. multipleSelection: []
  326. }
  327. },
  328. watch: {
  329. // 地址栏 url 发生变化时重新加载本页面
  330. $route() {
  331. this.$router.go()
  332. }
  333. },
  334. created() {
  335. const loginUser = getAuthedUser()
  336. if (loginUser != null) {
  337. this.currentUser = {
  338. userId: loginUser.userId,
  339. name: loginUser.screenName,
  340. avatar: loginUser.avatarUrl,
  341. author: true
  342. }
  343. }
  344. this.videoId = this.$route.params.id
  345. this.getVideoInfo(this.videoId)
  346. this.getSimilarVideos(this.videoId)
  347. this.getCommentWrapper(this.currentPage)
  348. },
  349. mounted() {
  350. const header = this.$refs.header
  351. if (header !== undefined && header !== null) {
  352. this.wrapStyle = `height: calc(100vh - ${header.clientHeight + 20}px)`
  353. }
  354. },
  355. methods: {
  356. handleSelectionChange(val) {
  357. this.multipleSelection = val
  358. },
  359. addToPlaylist() {
  360. if (this.multipleSelection.length === 0) {
  361. this.$message.info('请选择收藏夹')
  362. return
  363. }
  364. const jsonData = {}
  365. jsonData.albumId = []
  366. for (const item of this.multipleSelection) {
  367. jsonData.albumId.push(item.albumId)
  368. }
  369. jsonData.postId = this.videoId
  370. jsonData.action = 1
  371. collectItem(jsonData).then(resp => {
  372. if (resp.code === 0) {
  373. this.$notify.success({
  374. title: '视频已收藏',
  375. type: 'success',
  376. duration: 3000
  377. })
  378. } else {
  379. this.$notify.warning({
  380. title: '视频收藏失败',
  381. type: 'warning',
  382. duration: 3000
  383. })
  384. }
  385. }).catch(error => {
  386. this.$message.error(error)
  387. }).finally(() => {
  388. this.showPlaylistDialog = false
  389. })
  390. },
  391. // ****************************************************************************************************************
  392. handleCurrentChange(currentPage) {
  393. this.currentPage = currentPage
  394. this.getCommentWrapper(currentPage)
  395. // 回到顶部
  396. scrollTo(0, 0)
  397. },
  398. getCommentWrapper(pageNumber) {
  399. getComment(this.videoId, pageNumber).then(resp => {
  400. if (resp.code === 0) {
  401. const respData = resp.data
  402. this.dataList = respData.list
  403. this.totalSize = respData.totalSize
  404. } else {
  405. this.$notify({
  406. title: '提示',
  407. message: resp.msg,
  408. type: 'error',
  409. duration: 3000
  410. })
  411. }
  412. }).catch(error => {
  413. this.$notify({
  414. title: '提示',
  415. message: error.message,
  416. type: 'warning',
  417. duration: 3000
  418. })
  419. })
  420. },
  421. // ****************************************************************************************************************
  422. // 获取视频的详细信息
  423. getVideoInfo(videoId) {
  424. videoInfo(videoId).then(resp => {
  425. if (resp.code === 0) {
  426. this.video = resp.data
  427. document.title = resp.data.title
  428. this.userId = resp.data.userId
  429. getUserInfo(this.userId).then(resp => {
  430. if (resp.code === 0) {
  431. this.user = resp.data
  432. } else {
  433. this.$notify.error({
  434. message: '用户数据获取失败',
  435. type: 'warning',
  436. duration: 3000
  437. })
  438. }
  439. })
  440. } else if (resp.code === 2) {
  441. this.$router.push('/404')
  442. } else {
  443. this.permissionDenied = true
  444. }
  445. }).catch(error => {
  446. this.$notify.error({
  447. message: error.message,
  448. type: 'warning',
  449. duration: 3000
  450. })
  451. })
  452. },
  453. // 获取和当前视频类似的其他视频
  454. getSimilarVideos(videoId) {
  455. similarVideo(videoId).then(resp => {
  456. if (resp.code === 0) {
  457. this.similarVideos = resp.data
  458. } else {
  459. this.$notify.error({
  460. message: '推荐视频数据获取失败',
  461. type: 'warning',
  462. duration: 3000
  463. })
  464. }
  465. }).catch(error => {
  466. this.$notify.error({
  467. message: error.message,
  468. type: 'warning',
  469. duration: 3000
  470. })
  471. })
  472. },
  473. // 换一换
  474. refreshSimilar() {
  475. console.log('刷新相关推荐')
  476. },
  477. // 用户点击收藏
  478. collection(video) {
  479. if (video.collected) {
  480. this.$message.info('取消收藏')
  481. return
  482. }
  483. this.showPlaylistDialog = true
  484. const queryInfo = {
  485. pn: 1,
  486. userId: this.currentUser.userId
  487. }
  488. getUserPlaylist(queryInfo).then(resp => {
  489. if (resp.code === 0) {
  490. this.playlist = resp.data.list
  491. }
  492. })
  493. },
  494. getShareUrl(videoId) {
  495. getShortUrl(videoId).then(resp => {
  496. if (resp.code === 0) {
  497. console.log(resp.data)
  498. this.video.share += 1
  499. }
  500. })
  501. },
  502. getDownloadUrl(videoId) {
  503. // let filename
  504. downloadVideo(videoId).then(resp => {
  505. if (resp.code === 0) {
  506. const downloadUrl = resp.data.url
  507. window.open(downloadUrl, '_blank')
  508. /* fetch(downloadUrl.url, {
  509. headers: {
  510. Authorization: 'Bearer ' + downloadUrl.token
  511. },
  512. method: 'GET',
  513. credentials: 'include'
  514. }).then(resp => {
  515. /!*
  516. 遍历 formdata
  517. for (const key of resp.headers.keys()) {
  518. console.log(key + ' : ' + resp.headers.get(key))
  519. }*!/
  520. const header = resp.headers.get('Content-Disposition')
  521. const parts = header.split(';')
  522. const encodeFilename = parts[1].split('=')[1]
  523. filename = decodeURI(encodeFilename)
  524. return resp.blob()
  525. }).then(data => {
  526. const blobUrl = window.URL.createObjectURL(data)
  527. const a = document.createElement('a')
  528. a.download = filename
  529. a.href = blobUrl
  530. a.click()
  531. }).catch(e => {
  532. this.$notify({
  533. title: '提示',
  534. message: '视频下载失败',
  535. type: 'warning',
  536. duration: 3000
  537. })
  538. })*/
  539. } else {
  540. this.$notify({
  541. title: '提示',
  542. message: resp.msg,
  543. type: 'warning',
  544. duration: 3000
  545. })
  546. }
  547. }).catch(error => {
  548. this.$notify({
  549. title: '提示',
  550. message: error.message,
  551. type: 'error',
  552. duration: 3000
  553. })
  554. })
  555. },
  556. onCreateAlbum() {
  557. createAlbum(this.albumForm).then(resp => {
  558. if (resp.code === 0) {
  559. this.playlist.push(resp.data)
  560. }
  561. })
  562. this.albumForm.albumName = null
  563. },
  564. deleteVideo(video) {
  565. this.$confirm('确定要删除 ' + video.title + '?', '提示', {
  566. confirmButtonText: '确定',
  567. cancelButtonText: '取消',
  568. type: 'warning',
  569. customClass: 'msgbox'
  570. }).then(() => {
  571. const videoId = video.videoId
  572. const errorReportForm = {
  573. videoId: videoId,
  574. errorCode: 4
  575. }
  576. videoErrorDelete(errorReportForm).then(resp => {
  577. if (resp.code === 0) {
  578. this.errorReportForm.errorCode = null
  579. this.$notify({
  580. title: '提示',
  581. message: '视频错误已提交',
  582. type: 'warning',
  583. duration: 3000
  584. })
  585. } else {
  586. this.$notify({
  587. title: '提示',
  588. message: resp.msg,
  589. type: 'warning',
  590. duration: 3000
  591. })
  592. }
  593. }).catch(error => {
  594. this.$notify({
  595. title: '提示',
  596. message: error.message,
  597. type: 'warning',
  598. duration: 3000
  599. })
  600. })
  601. }).catch(() => {
  602. this.$message({
  603. type: 'info',
  604. message: '已取消'
  605. })
  606. })
  607. },
  608. displayErrorReportDialog() {
  609. this.errorReportForm.videoId = this.video.videoId
  610. this.showErrorReportDialog = true
  611. },
  612. submitErrorReport() {
  613. this.showErrorReportDialog = false
  614. videoErrorReport(this.errorReportForm).then(resp => {
  615. if (resp.code === 0) {
  616. this.errorReportForm.errorCode = null
  617. this.$notify({
  618. title: '提示',
  619. message: '视频错误已提交',
  620. type: 'warning',
  621. duration: 3000
  622. })
  623. } else {
  624. this.$notify({
  625. title: '提示',
  626. message: resp.msg,
  627. type: 'warning',
  628. duration: 3000
  629. })
  630. }
  631. }).catch(error => {
  632. this.$notify({
  633. title: '提示',
  634. message: error.message,
  635. type: 'warning',
  636. duration: 3000
  637. })
  638. })
  639. },
  640. // ****************************************************************************************************************
  641. // 评论
  642. async submit(newComment, parent, add) {
  643. const res = await new Promise((resolve) => {
  644. setTimeout(() => {
  645. resolve({ newComment, parent })
  646. }, 300)
  647. })
  648. add(Object.assign(res.newComment, { postId: this.video.videoId }))
  649. if (res.parent !== null) {
  650. // console.log('parent: ', res.parent)
  651. } else {
  652. this.totalSize += 1
  653. }
  654. // console.log('addComment: ', res)
  655. publishComment(res).then(resp => {
  656. if (resp.code === 0) {
  657. this.$notify.success({
  658. message: '评论已发布',
  659. duration: 3000
  660. })
  661. } else {
  662. this.$notify.warning({
  663. message: '评论发布失败',
  664. duration: 3000
  665. })
  666. }
  667. })
  668. },
  669. async like(comment) {
  670. const res = await new Promise((resolve) => {
  671. setTimeout(() => {
  672. resolve(comment)
  673. }, 0)
  674. })
  675. console.log('likeComment: ', res)
  676. },
  677. async uploadImg({ file, callback }) {
  678. const res = await new Promise((resolve, reject) => {
  679. const reader = new FileReader()
  680. reader.readAsDataURL(file)
  681. reader.onload = () => {
  682. resolve(reader.result)
  683. }
  684. reader.onerror = () => {
  685. reject(reader.error)
  686. }
  687. })
  688. callback(res)
  689. console.log('uploadImg: ', res)
  690. },
  691. async deleteComment(comment, parent) {
  692. const res = await new Promise((resolve) => {
  693. setTimeout(() => {
  694. resolve({ comment, parent })
  695. }, 300)
  696. })
  697. console.log('deleteComment: ', res)
  698. }
  699. // ****************************************************************************************************************
  700. }
  701. }
  702. </script>
  703. <style scoped>
  704. /*处于手机屏幕时*/
  705. @media screen and (max-width: 768px) {
  706. .movie-list {
  707. padding-top: 8px;
  708. padding-left: 0.5%;
  709. padding-right: 0.5%;
  710. }
  711. /* 或者使用这种更具体的选择器 */
  712. .el-dialog__wrapper .maintenance-dialog {
  713. width: 100% !important;
  714. margin-top: 5vh !important;
  715. }
  716. /* 表单布局优化 */
  717. .maintenance-dialog .el-form-item {
  718. margin-bottom: 15px;
  719. }
  720. .maintenance-dialog .el-form-item__label {
  721. float: none !important;
  722. display: block !important;
  723. text-align: left !important;
  724. padding: 0 0 8px !important;
  725. width: 100% !important;
  726. }
  727. .maintenance-dialog .el-form-item__content {
  728. margin-left: 0 !important;
  729. }
  730. /* 确保所有输入控件宽度100% */
  731. .maintenance-dialog .el-input,
  732. .maintenance-dialog .el-select,
  733. .maintenance-dialog .el-date-picker,
  734. .maintenance-dialog .el-input-number {
  735. width: 100% !important;
  736. }
  737. /* 调整按钮组间距 */
  738. .maintenance-dialog .dialog-footer {
  739. text-align: center;
  740. }
  741. .maintenance-dialog .dialog-footer .el-button {
  742. margin: 0 5px;
  743. }
  744. }
  745. .movie-list {
  746. padding-top: 15px;
  747. padding-left: 5%;
  748. padding-right: 5%;
  749. }
  750. .clearfix:before,
  751. .clearfix:after {
  752. display: table;
  753. content: "";
  754. }
  755. .clearfix:after {
  756. clear: both;
  757. }
  758. .tag{
  759. padding-top: 1px;
  760. padding-bottom: 1px;
  761. margin-left: 3px;
  762. margin-right: 3px;
  763. }
  764. </style>