index.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. let 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. unknowValueField: []
  122. }
  123. }
  124. })
  125. Toast.loading({
  126. message: '加载中...',
  127. forbidClick: true,
  128. loadingType: 'spinner',
  129. duration: 0
  130. })
  131. const obj = {
  132. policy: res.data.policy,
  133. signature: res.data.signature,
  134. key: key,
  135. KSSAccessKeyId: res.data.kssAccessKeyId,
  136. acl: 'public-read',
  137. name: fileName
  138. }
  139. let formData = new FormData()
  140. for (let key in obj) {
  141. formData.append(key, obj[key])
  142. }
  143. formData.append('file', file, fileName)
  144. await umiRequest(getOssUploadUrl(this.bucket), {
  145. method: 'POST',
  146. data: formData
  147. })
  148. console.log(getOssUploadUrl(this.bucket) + key)
  149. const uploadUrl = getOssUploadUrl(this.bucket) + key
  150. Toast.clear()
  151. this.$emit('update:modelValue', uploadUrl)
  152. this.onUploadChange(uploadUrl)
  153. } catch (error) {
  154. console.log(error, 'uploadFile')
  155. }
  156. }
  157. },
  158. render() {
  159. useCustomFieldValue(() => this.modelValue)
  160. return (
  161. <div class={styles['uploader-section']}>
  162. {this.modelValue && this.deletable ? (
  163. <Icon
  164. name="cross"
  165. onClick={this.onClose}
  166. class={styles['img-close']}
  167. />
  168. ) : null}
  169. {this.cropper && !this.native ? (
  170. <div class={styles['col-uploader']}>
  171. {this.modelValue ? (
  172. <Image
  173. fit="cover"
  174. position="center"
  175. class={styles.uploadImg}
  176. src={this.modelValue}
  177. />
  178. ) : (
  179. <div class={styles.uploader}>
  180. <Icon name={iconUploader} size="32" />
  181. <p class={styles.uploaderText}>{this.tips}</p>
  182. </div>
  183. )}
  184. <ColCropper option={this.options} getFile={this.getFile} />
  185. </div>
  186. ) : this.native ? (
  187. <div
  188. style={{
  189. display: 'flex',
  190. alignItems: 'center',
  191. justifyContent: 'center',
  192. height: '100%'
  193. }}
  194. onClick={this.nativeUpload}
  195. >
  196. {this.modelValue ? (
  197. <Image
  198. fit="cover"
  199. position="center"
  200. class={styles.uploadImg}
  201. src={this.modelValue}
  202. />
  203. ) : (
  204. <div class={styles.uploader}>
  205. <Icon name={iconUploader} size="32" />
  206. <p class={styles.uploaderText}>{this.tips}</p>
  207. </div>
  208. )}
  209. </div>
  210. ) : (
  211. <Uploader
  212. afterRead={this.afterRead}
  213. beforeRead={this.beforeRead}
  214. beforeDelete={this.beforeDelete}
  215. v-slots={{
  216. default: () =>
  217. this.modelValue ? (
  218. <Image
  219. fit="cover"
  220. position="center"
  221. class={styles.uploadImg}
  222. src={this.modelValue}
  223. />
  224. ) : (
  225. <div class={styles.uploader}>
  226. <Icon name={iconUploader} size="32" />
  227. <p class={styles.uploaderText}>{this.tips}</p>
  228. </div>
  229. )
  230. }}
  231. />
  232. )}
  233. </div>
  234. )
  235. }
  236. })