index.vue 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. <template>
  2. <a-upload
  3. :file-list="[]"
  4. :multiple="false"
  5. :before-upload="onBeforeUpload"
  6. :accept="extnames.map(ext => `.${ext}`).join(',')"
  7. >
  8. <a-button type="primary" :disabled="disabled || !!file">
  9. <upload-outlined></upload-outlined>
  10. 上传
  11. </a-button>
  12. </a-upload>
  13. <ol class="desc">
  14. <li>支持{{ extxTip }}文件格式;</li>
  15. <li>最大支持上传{{ maxSizeTip }};</li>
  16. <template v-if="tips">
  17. <li v-for="tip in tips" :key="tip">{{ tip }}</li>
  18. </template>
  19. </ol>
  20. <div v-if="file" class="action">
  21. <p>{{ typeof file === 'string' ? file : file.name }}</p>
  22. <delete-outlined
  23. v-if="!disabled"
  24. class="icon"
  25. @click="emit('update:file', undefined)"
  26. />
  27. </div>
  28. </template>
  29. <script lang="ts" setup>
  30. import { message } from 'ant-design-vue'
  31. import { getExtname } from '@/shared'
  32. import { computed } from 'vue'
  33. import type { UploadProps } from 'ant-design-vue'
  34. export type BUploadProps = {
  35. disabled?: boolean
  36. file?: File | string
  37. maxSize: number
  38. extnames: string | string[]
  39. tips?: string[]
  40. }
  41. const props = defineProps<BUploadProps>()
  42. const emit = defineEmits<{
  43. (e: 'update:file', v: BUploadProps['file']): void
  44. }>()
  45. const maxMB = computed(() => props.maxSize * 1024 * 1024)
  46. const maxSizeTip = computed(() =>
  47. props.maxSize > 1024 ? props.maxSize / 1024 + 'GB' : props.maxSize + 'MB'
  48. )
  49. const extnames = computed(() =>
  50. (Array.isArray(props.extnames) ? props.extnames : [props.extnames]).map(ext =>
  51. ext.toLowerCase()
  52. )
  53. )
  54. const extxTip = computed(
  55. () =>
  56. extnames.value.map(ext => `.${ext}`).join('、') +
  57. (extnames.value.length > 1 ? '等' : '')
  58. )
  59. const onBeforeUpload: UploadProps['beforeUpload'] = file => {
  60. const ext = getExtname(file.name)?.toLocaleLowerCase()
  61. if (!ext || !extnames.value.includes(ext)) {
  62. message.error(`仅支持${extxTip.value}文件格式`)
  63. } else if (file.size > maxMB.value) {
  64. message.error(`最大支持上传${maxSizeTip.value}`)
  65. } else {
  66. emit('update:file', file)
  67. }
  68. return false
  69. }
  70. </script>
  71. <style lang="scss" scoped>
  72. .desc {
  73. margin-top: 16px;
  74. color: #999999;
  75. padding-left: 20px;
  76. }
  77. .action {
  78. font-size: 14px;
  79. color: #323233;
  80. display: flex;
  81. align-items: center;
  82. p {
  83. margin: 0;
  84. word-break: break-all;
  85. }
  86. .icon {
  87. margin-left: 10px;
  88. color: #c8c8c8;
  89. cursor: pointer;
  90. transition: color 0.3s ease;
  91. &:hover {
  92. color: inherit;
  93. }
  94. }
  95. }
  96. </style>