upload.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /**
  2. * 文件上传处理函数
  3. */
  4. import { computed, ref, watch } from 'vue'
  5. import { File } from '@/api'
  6. import CipMessage from '../../../cip-message'
  7. import { isString } from '@cip/utils/util'
  8. import { useFormInject } from '../../../hooks/use-form'
  9. export const fileTypeList = ['png', 'jpg', 'jpeg', 'jpe', 'gif', 'doc', 'docx', 'ppt', 'pptx', 'pdf', 'xls', 'xlsx', 'zip', '7z', 'rar']
  10. export const uploadProps = (props, context) => {
  11. const { cipForm } = useFormInject()
  12. const useStringValue = computed(() => {
  13. return props.config?.stringValue
  14. })
  15. const objectValue = computed(() => { // 返回的数据是一个对象
  16. return props.config?.objectValue
  17. })
  18. const uploadFileFn = computed(() => {
  19. return props.config?.uploadFn || File.upload
  20. })
  21. const fileList = ref([])
  22. watch(() => props.modelValue, () => {
  23. if (props.modelValue) {
  24. if (!useStringValue.value) {
  25. // 兼容未配置stringValue但存储结果为string的modelValue
  26. if (isString(props.modelValue)) {
  27. fileList.value = props.modelValue.split(',').map(v => ({ url: v }))
  28. } else if (objectValue.value) {
  29. fileList.value = [props.modelValue]
  30. } else {
  31. fileList.value = props.modelValue
  32. }
  33. } else {
  34. fileList.value = props.modelValue.split(',').map(v => ({ url: v }))
  35. }
  36. } else {
  37. fileList.value = []
  38. }
  39. }, { immediate: true })
  40. // 文件上传
  41. const uploadFile = (info) => {
  42. let file = info.file
  43. const uid = info.file.uid
  44. console.log(cipForm)
  45. if (props.config?.getFileName) {
  46. file = new window.File([file], props.config?.getFileName(file.name, props.dependOnValues))
  47. }
  48. // 保持uid
  49. file.uid = uid
  50. const fileObject = {
  51. name: file.name,
  52. uid: file.uid,
  53. percentage: 0,
  54. status: ''
  55. }
  56. const fileXhr = uploadFileFn.value({
  57. file: file,
  58. dependOnValues: props.dependOnValues,
  59. config: {
  60. // 挂载监听钩子
  61. onUploadProgress: progress => {
  62. fileUploadProgress(info, { total: progress.total, loaded: progress.loaded, percentage: Math.floor(progress.loaded / progress.total * 100) })
  63. }
  64. }
  65. })
  66. fileObject.abort = fileXhr.abort
  67. fileList.value.push(fileObject)
  68. // 限制表单提交
  69. cipForm.uploadQueue[uid] = true
  70. fileXhr.send().then((res) => {
  71. fileUploadProgress(info, { url: res.data, status: 'success' })
  72. if (props.config.autoNotify) CipMessage.success(res.message)
  73. updateValue()
  74. }).catch(e => {
  75. fileUploadProgress(info, { status: 'exception' })
  76. setTimeout(() => {
  77. fileList.value.splice(fileList.value.findIndex(v => v.uid === info.file.uid), 1)
  78. }, 500)
  79. }).finally(() => {
  80. cipForm.uploadQueue[uid] = false
  81. })
  82. }
  83. // 单例模式加载message
  84. let messageInstance = null
  85. const mainMessage = (through, message) => {
  86. if (!through) {
  87. if (messageInstance) {
  88. CipMessage.closeAll()
  89. }
  90. messageInstance = CipMessage.warning(message)
  91. return true
  92. }
  93. }
  94. // 文件数量限制
  95. const countLimit = (file) => {
  96. // 加上正在上传的数量
  97. return fileList.value.length + 1 <= (props.config?.limit ?? Infinity)
  98. }
  99. // 文件类型限制
  100. const typeLimit = (file) => {
  101. if (props.config.ignoreFileType) { // 完全不限制类型
  102. return true
  103. }
  104. const fileType = props.config.fileType && props.config?.fileType.length !== 0 ? props.config?.fileType : fileTypeList
  105. const obj = file.name?.split('.') ?? ''
  106. return fileType.includes(obj[obj.length - 1])
  107. }
  108. // 文件大小限制
  109. const sizeLimit = (file) => {
  110. return file.size <= (props.config?.size ?? Infinity) * 1024 * 1024
  111. }
  112. // 修改文件列表某文件的状态
  113. const fileUploadProgress = (info, writeObj) => {
  114. return fileList.value.map(i => {
  115. if (i.uid === info.file.uid) {
  116. // eslint-disable-next-line
  117. for (const item in writeObj) {
  118. i[item] = writeObj[item]
  119. }
  120. }
  121. return i
  122. })
  123. }
  124. // 文件列表删除
  125. const removeFile = (file, list) => {
  126. const fileIndex = fileList.value.findIndex(v => v.uid === file.uid)
  127. fileList.value.splice(fileIndex, 1)
  128. updateValue()
  129. }
  130. const updateValue = () => {
  131. if (useStringValue.value) {
  132. context.emit('update:modelValue', fileList.value?.map(v => v.url).join(','))
  133. } else if (objectValue.value) {
  134. context.emit('update:modelValue', fileList.value[0])
  135. } else {
  136. context.emit('update:modelValue', fileList.value)
  137. }
  138. }
  139. return {
  140. uploadFile,
  141. removeFile,
  142. fileList,
  143. mainMessage,
  144. countLimit,
  145. typeLimit,
  146. sizeLimit
  147. }
  148. }
  149. export const download = (file) => {
  150. file.percentage = ''
  151. const download = document.createElement('a')
  152. download.setAttribute('href', file.url + '?response-content-type=application/octet-stream')
  153. download.setAttribute('download', file.name)
  154. download.click()
  155. }