UploadImageFormItem.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <template>
  2. <a-upload
  3. v-bind="customProps"
  4. :disabled="disabled"
  5. v-model:file-list="uploadSubImgList"
  6. list-type="picture-card"
  7. :class="uploadClass"
  8. :max-count="maxCount"
  9. :show-upload-list="!single"
  10. :customRequest="handleUpload"
  11. :before-upload="beforeUpload"
  12. @change="handleUploadSubImgChange"
  13. >
  14. <template v-if="single">
  15. <a-image v-if="value != ''"
  16. :src="(value as string)"
  17. alt="avatar"
  18. :width="singleImageSize.width"
  19. :height="singleImageSize.height"
  20. :preview="false"
  21. :fallback="failImage"
  22. />
  23. <div v-else :style="{ width: singleImageSize.width, height: singleImageSize.height }">
  24. <loading-outlined v-if="uploadingSubImg"></loading-outlined>
  25. <plus-outlined v-else></plus-outlined>
  26. <div class="ant-upload-text">上传</div>
  27. </div>
  28. </template>
  29. <template v-else>
  30. <loading-outlined v-if="uploadingSubImg"></loading-outlined>
  31. <plus-outlined v-else></plus-outlined>
  32. <div class="ant-upload-text">上传</div>
  33. </template>
  34. </a-upload>
  35. </template>
  36. <script lang="ts" setup>
  37. /**
  38. * 上传图片表单控件
  39. */
  40. import {
  41. stringUrlsToUploadedItems, type UploadCoInterface,
  42. type AntUploadRequestOption, type FileInfo, type FileItem
  43. } from './UploadImageFormItem';
  44. import { message, type UploadProps } from 'ant-design-vue';
  45. import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';
  46. import { type PropType, ref, onMounted, watch } from 'vue';
  47. import FailImage from '@/assets/images/imageFailed.png';
  48. const props = defineProps({
  49. /**
  50. * 是否禁用
  51. */
  52. disabled: {
  53. type: Boolean,
  54. default: false
  55. },
  56. /**
  57. * 预览图加载失败时显示图片
  58. */
  59. failImage: {
  60. type: String,
  61. default: () => FailImage,
  62. },
  63. /**
  64. * 上传工厂类
  65. */
  66. uploadCo: {
  67. type: Object as PropType<UploadCoInterface>,
  68. default: null,
  69. },
  70. /**
  71. * 上传之前的自定义检查回调
  72. * (file: FileItem) => boolean
  73. * 如果返回false,将停止上传
  74. */
  75. beforeUpload: {
  76. type: Function,
  77. default: null,
  78. },
  79. /**
  80. * 类样式
  81. */
  82. uploadClass: {},
  83. /**
  84. * 是否限制单图上传
  85. */
  86. single: {
  87. type: Boolean,
  88. default: false
  89. },
  90. /**
  91. * single 为false时,限制最多上传图片的数量
  92. */
  93. maxCount: {
  94. type: Number,
  95. default: 0,
  96. },
  97. /**
  98. * single 模式下图片显示大小
  99. */
  100. singleImageSize: {
  101. type: Object as PropType<{ width: number, height: number }>,
  102. default: () => ({ width: 100, height: 100 })
  103. },
  104. /**
  105. * 参数,可以是单张 string,多张 string[]
  106. */
  107. value: {},
  108. /**
  109. * a-upload 其他自定义参数
  110. */
  111. customProps: {
  112. type: Object as PropType<UploadProps>,
  113. default: null,
  114. },
  115. });
  116. const emits = defineEmits([
  117. 'update:value',
  118. ]);
  119. const uploadSubImgList = ref<FileItem[]>([]);
  120. const uploadingSubImg = ref(false);
  121. onMounted(() => {
  122. //将之前上传的图片包括URL设置到已上传列表中
  123. if (!props.single) {
  124. setTimeout(() => {
  125. uploadSubImgList.value = stringUrlsToUploadedItems(props.value instanceof Array ? (props.value as string[] || []) : [])
  126. }, 400);
  127. }
  128. });
  129. watch(() => props.value, () => {
  130. if (!props.single) {
  131. uploadSubImgList.value = stringUrlsToUploadedItems(props.value instanceof Array ? (props.value as string[] || []) : [])
  132. }
  133. });
  134. function handleUpload(requestOption: AntUploadRequestOption) {
  135. props.uploadCo?.uploadRequest(requestOption);
  136. }
  137. function handleUploadSubImgChange(info: FileInfo) {
  138. if (info.file.status === 'uploading') {
  139. uploadingSubImg.value = true;
  140. return;
  141. }
  142. if (info.file.status === 'removed') {
  143. if (props.single)
  144. emits('update:value', '');
  145. else
  146. emits('update:value', (props.value as string[] || []).filter(url => url != info.file.url));
  147. return;
  148. }
  149. if (info.file.status === 'done') {
  150. const url = props.uploadCo?.getUrlByUploadResponse(info.file.response) || '';
  151. if (props.single)
  152. emits('update:value', url);
  153. else
  154. emits('update:value', (props.value as string[] || []).concat([ url ]));
  155. uploadingSubImg.value = false;
  156. }
  157. if (info.file.status === 'error') {
  158. uploadingSubImg.value = false;
  159. message.error('上传失败!' + info.file.response);
  160. }
  161. }
  162. </script>