EditVideo.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. <template>
  2. <el-row class="movie-list">
  3. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  4. <el-col :md="24" style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  5. <el-card class="box-card">
  6. <div class="text item">
  7. <el-button style="float: left; padding: 3px 0" type="text" @click="onReturnVideo">返回视频稿件列表</el-button>
  8. </div>
  9. </el-card>
  10. </el-col>
  11. </el-row>
  12. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  13. <el-col :md="12" style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  14. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  15. <el-card class="box-card">
  16. <div slot="header" class="clearfix">
  17. <span>更新视频封面</span>
  18. <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateVideoCover">更新</el-button>
  19. </div>
  20. <div class="text item">
  21. <el-tooltip class="item" effect="dark" content="点击上传图片" placement="top-end">
  22. <el-upload
  23. class="avatar-uploader"
  24. :action="imgOssUrl"
  25. :headers="imgHeaders"
  26. :data="imgData"
  27. :with-credentials="true"
  28. :show-file-list="false"
  29. :before-upload="beforeAvatarUpload"
  30. :on-success="handleAvatarSuccess"
  31. :on-change="handleOnChange"
  32. >
  33. <img :src="coverUrl" class="avatar">
  34. </el-upload>
  35. </el-tooltip>
  36. </div>
  37. </el-card>
  38. </el-row>
  39. <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  40. <el-card class="box-card">
  41. <div slot="header" class="clearfix">
  42. <span>更新视频文件</span>
  43. <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateVideoFile">更新</el-button>
  44. </div>
  45. <div class="text item">
  46. <uploader
  47. class="uploader-example"
  48. :options="options"
  49. :auto-start="true"
  50. @file-added="onFileAdded"
  51. @file-success="onFileSuccess"
  52. @file-progress="onFileProgress"
  53. @file-error="onFileError"
  54. >
  55. <uploader-unsupport />
  56. <uploader-drop>
  57. <p>拖动视频文件到此处或</p>
  58. <uploader-btn :attrs="attrs">选择视频文件</uploader-btn>
  59. </uploader-drop>
  60. <uploader-list />
  61. </uploader>
  62. </div>
  63. </el-card>
  64. </el-row>
  65. </el-col>
  66. <el-col :md="12" style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
  67. <el-card class="box-card">
  68. <div slot="header" class="clearfix">
  69. <span>更新视频信息</span>
  70. <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateVideoInfo">更新</el-button>
  71. </div>
  72. <div class="text item">
  73. <el-form ref="form" :model="videoInfoForm" label-width="80px">
  74. <el-form-item label="标题">
  75. <el-input v-model="videoInfoForm.title" style="padding-right: 1px" placeholder="标题不能超过 50 个字符" />
  76. </el-form-item>
  77. <el-form-item label="描述">
  78. <el-input v-model="videoInfoForm.description" type="textarea" autosize style="padding-right: 1px;" />
  79. </el-form-item>
  80. <el-form-item label="发布时间">
  81. <el-date-picker
  82. v-model="videoInfoForm.pubDate"
  83. type="datetime"
  84. placeholder="选择发布的时间"
  85. />
  86. </el-form-item>
  87. </el-form>
  88. </div>
  89. </el-card>
  90. </el-col>
  91. </el-row>
  92. </el-row>
  93. </template>
  94. <script>
  95. import { getServerInfo } from '@/api/content'
  96. import { getVideoPost, updateVideoInfo, updateVideoCover, updateVideoFile } from '@/api/video'
  97. import {getVideoChannelInfo, getVideoCoverChannelInfo} from "@/api/file";
  98. export default {
  99. name: 'EditVideo',
  100. data() {
  101. return {
  102. // ****************************************************************************************************************
  103. options: null,
  104. attrs: {
  105. accept: 'video/*'
  106. },
  107. imgOssUrl: null,
  108. imgHeaders: {
  109. Authorization: ''
  110. },
  111. imgData: {
  112. channelId: process.env.VUE_APP_UPLOAD_COVER_CHANNEL
  113. },
  114. // ****************************************************************************************************************
  115. coverUrl: null,
  116. coverUrl1: null,
  117. coverFileId: null,
  118. videoFileId: null,
  119. // 提交给后端的数据
  120. videoInfoForm: {
  121. videoId: null,
  122. title: null,
  123. description: null,
  124. pubDate: null
  125. },
  126. ossToken: null
  127. }
  128. },
  129. created() {
  130. document.title = '编辑视频稿件'
  131. const videoId = this.$route.params.videoId
  132. getVideoPost(videoId).then(res => {
  133. if (res.code === 0) {
  134. const userVideoPost = res.data
  135. this.coverUrl = userVideoPost.coverUrl
  136. this.videoInfoForm.videoId = userVideoPost.videoId
  137. this.videoInfoForm.title = userVideoPost.title
  138. this.videoInfoForm.description = userVideoPost.description
  139. this.videoInfoForm.pubDate = userVideoPost.pubDate
  140. } else {
  141. this.$notify({
  142. title: '提示',
  143. message: '获取 OSS 服务器地址失败, 暂时无法上传文件',
  144. type: 'error',
  145. duration: 3000
  146. })
  147. }
  148. }).catch(error => {
  149. this.$notify({
  150. title: '提示',
  151. message: error.message,
  152. type: 'warning',
  153. duration: 3000
  154. })
  155. })
  156. getVideoChannelInfo().then(res => {
  157. if (res.code === 0) {
  158. const resData = res.data
  159. this.options = {
  160. target: resData.ossUrl,
  161. chunkSize: resData.maxSize,
  162. fileParameterName: 'file',
  163. testChunks: false,
  164. query: (file, chunk) => {
  165. return {
  166. channelId: this.form.channelId
  167. }
  168. },
  169. headers: {
  170. Authorization: 'Bearer ' + resData.token
  171. },
  172. withCredentials: false
  173. }
  174. } else {
  175. this.$notify({
  176. title: '提示',
  177. message: '获取 OSS 服务器地址失败, 暂时无法上传文件',
  178. type: 'error',
  179. duration: 3000
  180. })
  181. }
  182. }).catch(error => {
  183. this.$notify({
  184. title: '提示',
  185. message: '视频上传配置失败 ' + error.message,
  186. type: 'warning',
  187. duration: 3000
  188. })
  189. })
  190. getVideoCoverChannelInfo().then(res => {
  191. if (res.code === 0) {
  192. const resData = res.data
  193. this.imgOssUrl = resData.ossUrl
  194. this.imgHeaders.Authorization = 'Bearer ' + resData.token
  195. } else {
  196. this.$notify({
  197. title: '提示',
  198. message: '获取 OSS 服务器地址失败, 暂时无法上传文件',
  199. type: 'error',
  200. duration: 3000
  201. })
  202. }
  203. }).catch(error => {
  204. this.$notify({
  205. title: '提示',
  206. message: '图片上传配置失败 ' + error.message,
  207. type: 'warning',
  208. duration: 3000
  209. })
  210. })
  211. },
  212. methods: {
  213. // ****************************************************************************************************************
  214. onFileAdded(file) {
  215. if (file.file.size > 1024 * 1024 * 1024 * 5) {
  216. file.cancel()
  217. this.$notify(
  218. {
  219. title: '提示',
  220. message: '视频文件应小于 5GiB',
  221. type: 'warning',
  222. duration: 3000
  223. }
  224. )
  225. return
  226. }
  227. },
  228. onFileProgress(rootFile, file, chunk) {
  229. },
  230. onFileSuccess(rootFile, file, response, chunk) {
  231. const res = JSON.parse(response)
  232. if (res.code === 0) {
  233. const resData = res.data
  234. this.videoFileId = resData.uploadId
  235. this.$notify(
  236. {
  237. title: '提示',
  238. message: '视频已上传',
  239. type: 'warning',
  240. duration: 3000
  241. }
  242. )
  243. }
  244. },
  245. onFileError(rootFile, file, response, chunk) {
  246. this.$notify({
  247. title: '提示',
  248. message: '文件上传错误',
  249. type: 'warning',
  250. duration: 3000
  251. })
  252. },
  253. // ****************************************************************************************************************
  254. beforeAvatarUpload(file) {
  255. const isJPG = file.type === 'image/jpeg'
  256. const isLt2M = file.size / 1024 / 1024 < 2
  257. if (!isJPG) {
  258. this.$message.error('上传头像图片只能是 JPG 格式!')
  259. }
  260. if (!isLt2M) {
  261. this.$message.error('上传头像图片大小不能超过 2MB!')
  262. }
  263. return isJPG && isLt2M
  264. },
  265. handleAvatarSuccess(res, file) {
  266. const localImageUrl = URL.createObjectURL(file.raw)
  267. if (res.code === 0) {
  268. const resData = res.data
  269. this.coverFileId = resData.uploadId
  270. this.coverUrl = localImageUrl
  271. this.coverUrl1 = resData.url
  272. } else {
  273. this.$notify({
  274. title: '提示',
  275. message: '视频封面上传失败,请重试!' + res.msg,
  276. type: 'warning',
  277. duration: 3000
  278. })
  279. }
  280. },
  281. handleOnChange(file, fileList) {
  282. },
  283. // ****************************************************************************************************************
  284. onReturnVideo() {
  285. this.$router.push('/post/list/video')
  286. },
  287. onUpdateVideoInfo() {
  288. updateVideoInfo(this.videoInfoForm).then(res => {
  289. if (res.code === 0) {
  290. this.$notify({
  291. title: '提示',
  292. message: '视频信息已更新',
  293. type: 'warning',
  294. duration: 3000
  295. })
  296. }
  297. }).catch(error => {
  298. this.$notify({
  299. title: '提示',
  300. message: error.message,
  301. type: 'warning',
  302. duration: 3000
  303. })
  304. })
  305. },
  306. onUpdateVideoCover() {
  307. if (this.coverUrl1 === null) {
  308. this.$notify({
  309. title: '提示',
  310. message: '你还没有上传视频封面',
  311. type: 'warning',
  312. duration: 3000
  313. })
  314. return
  315. }
  316. const videoCover = {
  317. videoId: this.videoInfoForm.videoId,
  318. coverUrl: this.coverUrl1,
  319. coverFileId: this.coverFileId
  320. }
  321. updateVideoCover(videoCover).then(res => {
  322. if (res.code === 0) {
  323. this.$notify({
  324. title: '提示',
  325. message: '视频封面已更新',
  326. type: 'warning',
  327. duration: 3000
  328. })
  329. }
  330. }).catch(error => {
  331. this.$notify({
  332. title: '提示',
  333. message: error.message,
  334. type: 'warning',
  335. duration: 3000
  336. })
  337. })
  338. },
  339. onUpdateVideoFile() {
  340. if (this.videoFileId === null) {
  341. this.$notify({
  342. title: '提示',
  343. message: '你还没有上传视频文件',
  344. type: 'warning',
  345. duration: 3000
  346. })
  347. return
  348. }
  349. const videoFile = {
  350. videoId: this.videoInfoForm.videoId,
  351. videoFileId: this.videoFileId
  352. }
  353. updateVideoFile(videoFile).then(res => {
  354. if (res.code === 0) {
  355. this.$notify({
  356. title: '提示',
  357. message: '视频文件已更新',
  358. type: 'warning',
  359. duration: 3000
  360. })
  361. }
  362. }).catch(error => {
  363. this.$notify({
  364. title: '提示',
  365. message: error.message,
  366. type: 'warning',
  367. duration: 3000
  368. })
  369. })
  370. }
  371. }
  372. }
  373. </script>
  374. <style>
  375. /*处于手机屏幕时*/
  376. @media screen and (max-width: 768px){
  377. .movie-list {
  378. padding-top: 8px;
  379. padding-left: 0.5%;
  380. padding-right: 0.5%;
  381. }
  382. .coverImg {
  383. height: 120px !important;
  384. }
  385. }
  386. .movie-list {
  387. padding-top: 15px;
  388. padding-left: 6%;
  389. padding-right: 6%;
  390. }
  391. .uploader-example {
  392. width: 500px;
  393. padding: 15px;
  394. margin: 40px auto 0;
  395. font-size: 12px;
  396. box-shadow: 0 0 10px rgba(0, 0, 0, .4);
  397. }
  398. .uploader-example .uploader-btn {
  399. margin-right: 4px;
  400. }
  401. .uploader-example .uploader-list {
  402. max-height: 440px;
  403. overflow: auto;
  404. overflow-x: hidden;
  405. overflow-y: auto;
  406. }
  407. .avatar-uploader .el-upload {
  408. border: 1px dashed #d9d9d9;
  409. border-radius: 6px;
  410. cursor: pointer;
  411. position: relative;
  412. overflow: hidden;
  413. }
  414. .avatar-uploader .el-upload:hover {
  415. border-color: #409EFF;
  416. }
  417. .avatar-uploader-icon {
  418. font-size: 28px;
  419. color: #8c939d;
  420. width: 320px;
  421. height: 240px;
  422. line-height: 178px;
  423. text-align: center;
  424. }
  425. .avatar {
  426. width: 320px;
  427. height: 240px;
  428. display: block;
  429. }
  430. </style>