邃芒官网、邃芒慧影、口播(H5) https://m.metavatar.cc
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

291 Zeilen
8.0 KiB

  1. <template>
  2. <div :class="inPage ? 'page active' : 'page'">
  3. <div id="top"></div>
  4. <HeadTop />
  5. <div class="content">
  6. <!-- 视频 -->
  7. <div class="videoBox" v-if="videoSrc">
  8. <div id="player-container" />
  9. <!-- 下载按钮 -->
  10. <!-- <a :href="videoSrc" download class="videoBox-download">
  11. <img src="../../assets/icon/icon-download.png" alt="" />
  12. </a> -->
  13. <!-- <a class="videoBox-download" :href="videoSrc" download
  14. ><img src="../../assets/icon/icon-download.png" alt=""
  15. /></a> -->
  16. <div class="videoBox-download" @click="downloadVideo">
  17. <img src="../../assets/icon/icon-download.png" alt="" />
  18. </div>
  19. </div>
  20. </div>
  21. </div>
  22. </template>
  23. <script>
  24. import Vue from 'vue'
  25. import { Toast, Dialog } from 'vant'
  26. import { mapState, mapActions } from 'vuex'
  27. import HeadTop from './../../components/common/head.vue'
  28. // 工具
  29. import { scrollToID, getDeviceType } from '../../utils'
  30. import { saveAs } from 'file-saver'
  31. // 接口
  32. import { getModelDetailById } from '../../api/getPaper'
  33. import { doGetVideoDetialById } from '../../api/downloadVideo'
  34. Vue.use(Toast)
  35. export default {
  36. components: {
  37. HeadTop
  38. },
  39. data() {
  40. return {
  41. inPage: false,
  42. // videoSrc:
  43. // 'https://wenlian.wenzhou.gov.cn:8001//upload/video/%E3%80%8A%E7%93%AF%E8%B6%8A%E4%B9%8B%E5%8D%8E%E3%80%8B%E7%89%87%E8%8A%B11.mp4',
  44. videoSrc: null, //播放地址路径
  45. title: null, // 视频名称
  46. coverUrl: null //封面图
  47. }
  48. },
  49. computed: {
  50. ...mapState({
  51. characters: (state) => state.publicObj.characters
  52. })
  53. },
  54. created() {},
  55. async mounted() {
  56. this.inPage = true
  57. scrollToID('top')
  58. //初始化数据
  59. await this.getVideoInfo()
  60. this.open()
  61. },
  62. destroyed() {},
  63. methods: {
  64. // 创建阿里云播放器
  65. open() {
  66. // 检测设备类型
  67. const deviceType = getDeviceType()
  68. let isAndroid = false
  69. if (!deviceType) {
  70. // 设备类型为pc
  71. isAndroid = false
  72. } else {
  73. if (deviceType[0] == 'Android') {
  74. // 设备类型为安卓
  75. isAndroid = true
  76. } else {
  77. // 其他设备
  78. isAndroid = false
  79. }
  80. }
  81. new Aliplayer(
  82. {
  83. id: 'player-container',
  84. cover: this.coverUrl,
  85. source: this.videoSrc,
  86. // 安卓设备尺寸比其他设备小一半,需适配
  87. // width: isAndroid ? '260px' : '480px',
  88. // height: isAndroid ? '427px' : '854px',
  89. width: '100%',
  90. height: '100%',
  91. // 以下可选设置
  92. playsinline: true, // 禁止内置播放
  93. isLive: false, // 直播
  94. rePlay: false, // 循环播放
  95. useH5Prism: true, // 开启H5播放器
  96. preload: true, //播放器自动加载
  97. autoplay: false, // 自动播放
  98. diagnosisButtonVisible: false, //是否显示检测按钮
  99. keyShortCuts: true, //是否启用快捷键
  100. keyFastForwardStep: 3, //快进快退的时间长度
  101. controlBarVisibility: 'always' // 控制条的显示方式
  102. },
  103. function (player) {
  104. player.play()
  105. }
  106. )
  107. },
  108. // 下载视频
  109. async downloadVideo() {
  110. // 视频地址
  111. let that = this
  112. const videoUrl = this.videoSrc
  113. const title = this.sanitizeFilename(this.title)
  114. // ios
  115. const deviceType = getDeviceType()
  116. let isAndroid = false
  117. if (!deviceType) {
  118. // 设备类型为pc
  119. isAndroid = false
  120. } else {
  121. if (deviceType[0] == 'Android') {
  122. // 设备类型为安卓
  123. isAndroid = true
  124. } else {
  125. // 其他设备
  126. isAndroid = false
  127. }
  128. }
  129. if (!isAndroid) {
  130. console.log('ios')
  131. // await this.downloadFun(
  132. // this.videoSrc + '?response-content-type=application/octet-stream',
  133. // this.title + '.mp4'
  134. // )
  135. // await this.downloadFile1(this.videoSrc)
  136. window.open(this.videoSrc, '_self')
  137. } else {
  138. // 下载视频
  139. saveAs(videoUrl, this.title + '.mp4')
  140. }
  141. },
  142. // 视频名转化
  143. sanitizeFilename(filename) {
  144. return filename.replace(/[/\\:?*"<>|]/g, '').trim()
  145. },
  146. // ios下载处理
  147. downloadFile1(url) {
  148. return new Promise((resolve, reject) => {
  149. const xhr = new XMLHttpRequest()
  150. xhr.open('GET', url, true)
  151. xhr.responseType = 'arraybuffer'
  152. xhr.onload = () => {
  153. if (xhr.status === 200) {
  154. const contentType = xhr.getResponseHeader('Content-Type')
  155. const blob = new Blob([xhr.response], { type: contentType })
  156. const reader = new FileReader()
  157. reader.readAsDataURL(blob)
  158. reader.onloadend = function () {
  159. const base64Data = reader.result
  160. const link = document.createElement('a')
  161. link.href = base64Data
  162. link.download = fileName
  163. document.body.appendChild(link)
  164. link.click()
  165. document.body.removeChild(link)
  166. }
  167. resolve(blob)
  168. } else {
  169. reject(
  170. new Error(`Failed to download file, status code: ${xhr.status}`)
  171. )
  172. }
  173. }
  174. xhr.onerror = () => {
  175. reject(new Error(`Failed to download file, network error`))
  176. }
  177. xhr.send()
  178. })
  179. },
  180. async downloadFun(blobFile, fileName) {
  181. let blob = new Blob([blobFile], {
  182. type: 'application/pdf;charset=UTF-8'
  183. })
  184. console.log(blob)
  185. if (window.navigator.msSaveOrOpenBlob) {
  186. navigator.msSaveBlob(blob, fileName)
  187. } else {
  188. const reader = new FileReader()
  189. reader.readAsDataURL(blob)
  190. reader.onloadend = function () {
  191. const base64Data = reader.result
  192. const link = document.createElement('a')
  193. link.href = base64Data
  194. link.download = fileName
  195. document.body.appendChild(link)
  196. link.click()
  197. document.body.removeChild(link)
  198. }
  199. // const dataUrl = 'data:application/octet-stream;base64,' + blobFile
  200. // const a = document.createElement('a')
  201. // a.style.display = 'none'
  202. // a.href = dataUrl
  203. // a.download = fileName
  204. // document.body.appendChild(a)
  205. // a.click()
  206. // window.URL.revokeObjectURL(dataUrl)
  207. // document.body.removeChild(a)
  208. // let link = document.createElement('a')
  209. // // link.href = blobFile
  210. // link.href = window.URL.createObjectURL(blob)
  211. // link.download = fileName
  212. // link.click()
  213. // window.URL.revokeObjectURL(link.href) //释放内存
  214. }
  215. },
  216. // 获取视频信息
  217. async getVideoInfo() {
  218. const { data: res } = await getModelDetailById(this.$route.query.id)
  219. if (res.videoId) {
  220. const { data: res2 } = await doGetVideoDetialById(res.videoId)
  221. this.videoSrc = res2.videoUrl
  222. this.title = res2.title
  223. this.coverUrl = res2.coverURL
  224. return
  225. }
  226. this.videoSrc = res.videoPathUri + res.videoPath
  227. this.title = res.title
  228. this.coverUrl = res.coverURL
  229. },
  230. // 处理时间
  231. formatTime(time) {
  232. const minutes = Math.floor(time / 60)
  233. const seconds = Math.round(time % 60)
  234. return `${minutes}:${seconds.toString().padStart(2, '0')}`
  235. },
  236. ...mapActions(['setCharacters']),
  237. go(url) {
  238. this.$router.push(url)
  239. }
  240. }
  241. }
  242. </script>
  243. <style lang="scss" scoped>
  244. #player-container {
  245. width: 100%;
  246. height: calc(100vh - 40px);
  247. overflow: hidden;
  248. }
  249. .page {
  250. // width: 375px;
  251. // height: 100vh;
  252. overflow: hidden;
  253. }
  254. .content {
  255. width: 100%;
  256. height: calc(100vh - 40px);
  257. overflow: hidden;
  258. }
  259. .videoBox {
  260. position: relative;
  261. width: 100%;
  262. height: calc(100vh - 40px);
  263. background-color: #f8f9f9;
  264. &-download {
  265. position: absolute;
  266. right: 15px;
  267. top: 15px;
  268. display: inline-block;
  269. width: 24px;
  270. height: 24px;
  271. z-index: 99;
  272. img {
  273. width: 100%;
  274. height: 100%;
  275. }
  276. }
  277. }
  278. </style>