| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- <script setup lang="ts">
- import { inject, onBeforeUnmount, ref, watch } from 'vue'
- import { Upload, Delete } from '@element-plus/icons-vue'
- import type { Attachment } from '../api/indexType'
- import { createUploadId, uploadImage } from '../utils/upload'
- import { report } from '../utils/ui'
- import { uploadsKey } from '../utils/uploads'
- const props = defineProps<{ active: boolean; disabled?: boolean }>()
- const pendingUploads = inject(uploadsKey)
- let generation = 0
- function invalidate() { generation += 1 }
- watch(() => props.active, invalidate, { flush: 'sync' })
- onBeforeUnmount(invalidate)
- const model = defineModel<Attachment[]>({ required: true })
- const busy = ref(false)
- async function select(event : Event) {
- if (busy.value || props.disabled || !props.active) return
- const input = event.target as HTMLInputElement
- const currentGeneration = generation
- busy.value = true
- if (pendingUploads) pendingUploads.value += 1
- try {
- for (const file of Array.from(input.files || [])) {
- const url = await uploadImage(file)
- if (currentGeneration !== generation || !props.active) return
- model.value = [...model.value, { id: createUploadId(), name: file.name, url }]
- }
- }
- catch (error) { if (currentGeneration === generation) report(error) }
- finally { busy.value = false; input.value = ''; if (pendingUploads) pendingUploads.value -= 1 }
- }
- </script>
- <template>
- <div class="evidence">
- <label class="upload-button">
- <el-icon>
- <Upload />
- </el-icon>{{ busy ? '上传中…' : '上传图片' }}
- <input type="file" accept="image/png,image/jpeg,image/webp" multiple :disabled="busy || disabled" @change="select">
- </label>
- <div v-for="(file, index) in model" :key="file.id" class="attachment">
- <el-image :src="file.url" :preview-src-list="model.map(item => item.url)" :initial-index="index"
- preview-teleported fit="cover" />
- <el-button :disabled="busy || disabled" :icon="Delete" text aria-label="移除图片" title="移除图片"
- @click="model = model.filter(item => item.id !== file.id)" />
- </div>
- </div>
- </template>
|