index.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import request from '@/helpers/request'
  2. import { Icon, Toast, Uploader, Image } from 'vant'
  3. import { defineComponent } from 'vue'
  4. import styles from './index.module.less'
  5. import { useCustomFieldValue } from '@vant/use'
  6. import { browser } from '@/helpers/utils'
  7. import umiRequest from 'umi-request'
  8. import iconUploader from '@common/images/icon_uploader_video.png'
  9. import iconUploadPoster from '@common/images/icon_upload_poster.png'
  10. import { postMessage } from '@/helpers/native-message'
  11. import { getOssUploadUrl, state } from '@/state'
  12. import { getUploadSign, onOnlyFileUpload } from '@/helpers/oss-file-upload'
  13. export default defineComponent({
  14. name: 'ColUploadVideo',
  15. props: {
  16. modelValue: String,
  17. posterUrl: String,
  18. tips: {
  19. type: String,
  20. default: '点击上传'
  21. },
  22. nativeUpload: {
  23. // 是否使用原生上传, 且当前环境为app才会生效
  24. type: Boolean,
  25. default: true
  26. },
  27. size: {
  28. type: Number,
  29. default: 30
  30. },
  31. deletable: {
  32. type: Boolean,
  33. default: true
  34. },
  35. bucket: {
  36. type: String,
  37. default: 'daya'
  38. }
  39. },
  40. methods: {
  41. beforeRead(file: any) {
  42. const isLt2M = file.size / 1024 / 1024 < this.size
  43. // console.log(this.size)
  44. if (!isLt2M) {
  45. Toast(`上传视频大小不能超过 ${this.size}MB`)
  46. return false
  47. }
  48. return true
  49. },
  50. beforeDelete(file: any, detail: { index: any }) {
  51. // this.dataModel.splice(detail.index, 1)
  52. return true
  53. },
  54. async afterRead(file: any, detail: any) {
  55. try {
  56. file.status = 'uploading'
  57. file.message = '上传中...'
  58. // 获取签名
  59. // const signUrl =
  60. // state.platformType === 'TEACHER'
  61. // ? '/api-teacher/getUploadSign'
  62. // : '/api-student/getUploadSign'
  63. const fileName = file.file.name.replaceAll(' ', '_')
  64. const key = new Date().getTime() + fileName
  65. console.log(file)
  66. // const res = await request.post(signUrl, {
  67. // data: {
  68. // filename: fileName,
  69. // bucketName: this.bucket,
  70. // postData: {
  71. // filename: fileName,
  72. // acl: 'public-read',
  73. // key: key
  74. // }
  75. // }
  76. // })
  77. const { data } = await getUploadSign({
  78. filename: key,
  79. bucketName: this.bucket,
  80. postData: {
  81. filename: key,
  82. acl: 'public-read',
  83. key: key
  84. }
  85. }, true)
  86. setTimeout(() => {
  87. Toast.loading({
  88. message: '加载中...',
  89. forbidClick: true,
  90. loadingType: 'spinner',
  91. duration: 0
  92. })
  93. }, 100);
  94. const obj = {
  95. policy: data.policy,
  96. signature: data.signature,
  97. key: key,
  98. KSSAccessKeyId: data.kssAccessKeyId,
  99. acl: 'public-read',
  100. name: key,
  101. file: file.file
  102. }
  103. const uploadUrl = await onOnlyFileUpload(
  104. getOssUploadUrl(this.bucket),
  105. obj
  106. )
  107. Toast.clear()
  108. this.$emit('update:modelValue', uploadUrl)
  109. } catch (error) {
  110. //
  111. console.log(error)
  112. }
  113. },
  114. onClose(e: any) {
  115. this.$emit('update:modelValue', null)
  116. e.stopPropagation()
  117. },
  118. onNativeUpload() {
  119. postMessage(
  120. { api: 'chooseFile', content: { type: 'video', bucket: this.bucket } },
  121. (res: any) => {
  122. // this.posterUrlInner = res.firstFrameImg
  123. this.$emit('update:modelValue', res.fileUrl)
  124. // this.$emit('update:posterUrl', res.firstFrameImg)
  125. }
  126. )
  127. },
  128. getVideoBase64(url: string) {
  129. return new Promise(function (resolve) {
  130. let dataURL = ''
  131. const video = document.createElement('video')
  132. video.setAttribute('crossOrigin', 'anonymous') // 处理跨域
  133. video.setAttribute('src', url)
  134. video.setAttribute('preload', 'auto')
  135. video.addEventListener('loadeddata', function () {
  136. console.log(video, 'video loadeddata')
  137. const canvas = document.createElement('canvas')
  138. console.log('video.clientWidth', video.videoWidth) // 视频宽
  139. console.log('video.clientHeight', video.videoHeight) // 视频高
  140. const width = video.videoWidth || 750 // canvas的尺寸和图片一样
  141. const height = video.videoHeight || 500 // 设置默认宽高为 750 * 500
  142. canvas.width = width
  143. canvas.height = height
  144. ;(canvas as any)
  145. .getContext('2d')
  146. .drawImage(video, 0, 0, width, height) // 绘制canvas
  147. dataURL = canvas.toDataURL('image/jpeg') // 转换为base64
  148. resolve(dataURL)
  149. })
  150. })
  151. }
  152. },
  153. render() {
  154. useCustomFieldValue(() => this.modelValue)
  155. return (
  156. <div class={styles['uploader-section']}>
  157. {this.modelValue && this.deletable ? (
  158. <Icon
  159. name="cross"
  160. onClick={this.onClose}
  161. class={styles['img-close']}
  162. />
  163. ) : null}
  164. {browser().isApp && this.nativeUpload ? (
  165. <div onClick={this.onNativeUpload} style={{ height: '100%' }}>
  166. {this.modelValue ? (
  167. <video
  168. ref="videoUpload"
  169. class={styles.uploadImg}
  170. src={this.modelValue + '#t=1,4'}
  171. // poster={iconUploadPoster}
  172. />
  173. ) : (
  174. <div class={styles.uploader}>
  175. <Icon name={iconUploader} size="32" />
  176. <p class={styles.uploaderText}>{this.tips}</p>
  177. </div>
  178. )}
  179. </div>
  180. ) : (
  181. <>
  182. {/* @ts-ignore */}
  183. <Uploader
  184. accept=".mp4"
  185. afterRead={this.afterRead}
  186. beforeRead={this.beforeRead}
  187. beforeDelete={this.beforeDelete}
  188. v-slots={{
  189. default: () =>
  190. this.modelValue ? (
  191. <video
  192. ref="videoUpload"
  193. class={styles.uploadImg}
  194. src={this.modelValue + '#t=1,4'}
  195. // onLoad={() => {
  196. // Toast.clear()
  197. // }}
  198. />
  199. ) : (
  200. <div class={styles.uploader}>
  201. <Icon name={iconUploader} size="32" />
  202. <p class={styles.uploaderText}>{this.tips}</p>
  203. </div>
  204. )
  205. }}
  206. />
  207. </>
  208. )}
  209. </div>
  210. )
  211. }
  212. })