index.vue 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. {{ $t('sys.uploadBtn') }}
  11. </a-button>
  12. </a-upload>
  13. <ol class="desc">
  14. <li>{{ $t('sys.uploadDesc.0', { extxTip }) }}</li>
  15. <li>{{ $t('sys.uploadDesc.1', { 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. import { ui18n } from '@/lang'
  35. export type BUploadProps = {
  36. disabled?: boolean
  37. file?: File | string
  38. maxSize: number
  39. extnames: string | string[]
  40. tips?: string[]
  41. }
  42. const props = defineProps<BUploadProps>()
  43. const emit = defineEmits<{
  44. (e: 'update:file', v: BUploadProps['file']): void
  45. }>()
  46. const maxMB = computed(() => props.maxSize * 1024 * 1024)
  47. const maxSizeTip = computed(() =>
  48. props.maxSize > 1024 ? props.maxSize / 1024 + 'GB' : props.maxSize + 'MB'
  49. )
  50. const extnames = computed(() =>
  51. (Array.isArray(props.extnames) ? props.extnames : [props.extnames]).map(ext =>
  52. ext.toLowerCase()
  53. )
  54. )
  55. const extxTip = computed(
  56. () =>
  57. extnames.value.map(ext => `.${ext}`).join('、') +
  58. (extnames.value.length > 1 ? ui18n.t('sys.more') : '')
  59. )
  60. const onBeforeUpload: UploadProps['beforeUpload'] = file => {
  61. const ext = getExtname(file.name)?.toLocaleLowerCase()
  62. if (!ext || !extnames.value.includes(ext)) {
  63. message.error(ui18n.t('sys.noUploadDesc[0]', { extxTip: extxTip.value }))
  64. } else if (file.size > maxMB.value) {
  65. message.error(
  66. ui18n.t('sys.noUploadDesc[1]', { maxSizeTip: maxSizeTip.value })
  67. )
  68. } else {
  69. emit('update:file', file)
  70. }
  71. return false
  72. }
  73. </script>
  74. <style lang="scss" scoped>
  75. .desc {
  76. margin-top: 16px;
  77. color: #999999;
  78. padding-left: 20px;
  79. }
  80. .action {
  81. font-size: 14px;
  82. color: #323233;
  83. display: flex;
  84. align-items: center;
  85. p {
  86. margin: 0;
  87. word-break: break-all;
  88. }
  89. .icon {
  90. font-size: 1.2em;
  91. margin-left: 10px;
  92. color: #ff4d4f;
  93. cursor: pointer;
  94. transition: color 0.3s ease;
  95. &:hover {
  96. color: #ff7875;
  97. }
  98. &:active {
  99. color: #d9363e;
  100. }
  101. }
  102. }
  103. </style>