index.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import { Icon, Image, Toast, Uploader } from 'vant'
  2. import { defineComponent } from 'vue'
  3. import styles from './index.module.less'
  4. import ColCropper from '../col-cropper'
  5. import { useCustomFieldValue } from '@vant/use'
  6. import { postMessage } from '@/helpers/native-message'
  7. import umiRequest from 'umi-request'
  8. import iconUploader from '@common/images/icon_uploader.png'
  9. import request from '@/helpers/request'
  10. import { getOssUploadUrl, state } from '@/state'
  11. export default defineComponent({
  12. name: 'col-upload',
  13. props: {
  14. modelValue: String,
  15. tips: {
  16. type: String,
  17. default: '点击上传'
  18. },
  19. deletable: {
  20. type: Boolean,
  21. default: true
  22. },
  23. native: {
  24. // 是否原生上传
  25. type: Boolean,
  26. default: false
  27. },
  28. cropper: {
  29. // 是否进行裁切
  30. type: Boolean,
  31. default: false
  32. },
  33. options: {
  34. // 裁切需要参数
  35. type: Object,
  36. default: {}
  37. },
  38. uploadSize: {
  39. // 上传图片大小
  40. type: Number,
  41. default: 5
  42. },
  43. onUploadChange: {
  44. type: Function,
  45. default: (url: string) => {}
  46. },
  47. bucket: {
  48. type: String,
  49. default: 'daya'
  50. }
  51. },
  52. methods: {
  53. nativeUpload() {
  54. postMessage(
  55. {
  56. api: 'chooseFile',
  57. content: { type: 'img', max: 1, bucket: this.bucket }
  58. },
  59. (res: any) => {
  60. console.log(res, 'fileUrl')
  61. this.$emit('update:modelValue', res.fileUrl)
  62. }
  63. )
  64. },
  65. beforeRead(file: any) {
  66. console.log(file, 'beforeRead')
  67. const isLt2M = file.size / 1024 / 1024 < this.uploadSize
  68. if (!isLt2M) {
  69. Toast(`上传文件大小不能超过 ${this.uploadSize}MB`)
  70. return false
  71. }
  72. return true
  73. },
  74. beforeDelete(file: any, detail: { index: any }) {
  75. // this.dataModel.splice(detail.index, 1)
  76. return true
  77. },
  78. async afterRead(file: any, detail: any) {
  79. try {
  80. file.status = 'uploading'
  81. file.message = '上传中...'
  82. await this.uploadFile(file.file)
  83. } catch (error) {
  84. //
  85. console.log(error, '2323')
  86. Toast.clear()
  87. }
  88. },
  89. onClose(e: any) {
  90. this.$emit('update:modelValue', null)
  91. this.onUploadChange()
  92. e.stopPropagation()
  93. },
  94. async getFile(file: any) {
  95. try {
  96. await this.uploadFile(file)
  97. } catch {
  98. //
  99. }
  100. },
  101. async uploadFile(file: any) {
  102. // 上传文件
  103. try {
  104. // 获取签名
  105. const signUrl =
  106. state.platformType === 'TEACHER'
  107. ? '/api-teacher/getUploadSign'
  108. : '/api-student/getUploadSign'
  109. const tempName = file.name || ''
  110. const fileName = tempName && tempName.replace(/ /gi, '_')
  111. const key = new Date().getTime() + fileName
  112. console.log(file)
  113. const res = await request.post(signUrl, {
  114. data: {
  115. filename: fileName,
  116. bucketName: this.bucket,
  117. postData: {
  118. filename: fileName,
  119. acl: 'public-read',
  120. key: key
  121. }
  122. }
  123. })
  124. Toast.loading({
  125. message: '加载中...',
  126. forbidClick: true,
  127. loadingType: 'spinner',
  128. duration: 0
  129. })
  130. const obj = {
  131. policy: res.data.policy,
  132. signature: res.data.signature,
  133. key: key,
  134. KSSAccessKeyId: res.data.kssAccessKeyId,
  135. acl: 'public-read',
  136. name: fileName
  137. }
  138. const formData = new FormData()
  139. for (const key in obj) {
  140. formData.append(key, obj[key])
  141. }
  142. formData.append('file', file, fileName)
  143. await umiRequest(getOssUploadUrl(this.bucket), {
  144. method: 'POST',
  145. data: formData
  146. })
  147. console.log(getOssUploadUrl(this.bucket) + key)
  148. const uploadUrl = getOssUploadUrl(this.bucket) + key
  149. Toast.clear()
  150. this.$emit('update:modelValue', uploadUrl)
  151. this.onUploadChange(uploadUrl)
  152. } catch (error) {
  153. console.log(error, 'uploadFile')
  154. }
  155. }
  156. },
  157. render() {
  158. useCustomFieldValue(() => this.modelValue)
  159. return (
  160. <div class={styles['uploader-section']}>
  161. {this.modelValue && this.deletable ? (
  162. <Icon
  163. name="cross"
  164. onClick={this.onClose}
  165. class={styles['img-close']}
  166. />
  167. ) : null}
  168. {this.cropper && !this.native ? (
  169. <div class={styles['col-uploader']}>
  170. {this.modelValue ? (
  171. <Image
  172. fit="cover"
  173. position="center"
  174. class={styles.uploadImg}
  175. src={this.modelValue}
  176. />
  177. ) : (
  178. <div class={styles.uploader}>
  179. <Icon name={iconUploader} size="32" />
  180. <p class={styles.uploaderText}>{this.tips}</p>
  181. </div>
  182. )}
  183. <ColCropper option={this.options} getFile={this.getFile} />
  184. </div>
  185. ) : this.native ? (
  186. <div
  187. style={{
  188. display: 'flex',
  189. alignItems: 'center',
  190. justifyContent: 'center',
  191. height: '100%'
  192. }}
  193. onClick={this.nativeUpload}
  194. >
  195. {this.modelValue ? (
  196. <Image
  197. fit="cover"
  198. position="center"
  199. class={styles.uploadImg}
  200. src={this.modelValue}
  201. />
  202. ) : (
  203. <div class={styles.uploader}>
  204. <Icon name={iconUploader} size="32" />
  205. <p class={styles.uploaderText}>{this.tips}</p>
  206. </div>
  207. )}
  208. </div>
  209. ) : (
  210. <Uploader
  211. afterRead={this.afterRead}
  212. beforeRead={this.beforeRead}
  213. beforeDelete={this.beforeDelete}
  214. v-slots={{
  215. default: () =>
  216. this.modelValue ? (
  217. <Image
  218. fit="cover"
  219. position="center"
  220. class={styles.uploadImg}
  221. src={this.modelValue}
  222. />
  223. ) : (
  224. <div class={styles.uploader}>
  225. <Icon name={iconUploader} size="32" />
  226. <p class={styles.uploaderText}>{this.tips}</p>
  227. </div>
  228. )
  229. }}
  230. />
  231. )}
  232. </div>
  233. )
  234. }
  235. })