| | |
| | | <template> |
| | | <div> |
| | | <Space> |
| | | <a-button type="primary" @click="openUploadModal" preIcon="carbon:cloud-upload"> |
| | | <a-button |
| | | type="primary" |
| | | @click="openUploadModal" |
| | | preIcon="carbon:cloud-upload" |
| | | :disabled="disabled" |
| | | > |
| | | {{ t('component.upload.upload') }} |
| | | </a-button> |
| | | <Tooltip placement="bottom" v-if="showPreview"> |
| | |
| | | <UploadModal |
| | | v-bind="bindValue" |
| | | :previewFileList="fileList" |
| | | :fileListOpenDrag="fileListOpenDrag" |
| | | :fileListDragOptions="fileListDragOptions" |
| | | @register="registerUploadModal" |
| | | @change="handleChange" |
| | | @delete="handleDelete" |
| | |
| | | |
| | | <UploadPreviewModal |
| | | :value="fileList" |
| | | :max-number="bindValue.maxNumber" |
| | | @register="registerPreviewModal" |
| | | @list-change="handlePreviewChange" |
| | | @delete="handlePreviewDelete" |
| | | :preview-columns="props.previewColumns" |
| | | :before-preview-data="props.beforePreviewData" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <script lang="ts"> |
| | | import { defineComponent, ref, watch, unref, computed } from 'vue'; |
| | | <script lang="ts" setup> |
| | | import { ref, watch, unref, computed, useAttrs } from 'vue'; |
| | | import { Recordable } from '@vben/types'; |
| | | import Icon from '@/components/Icon/Icon.vue'; |
| | | import { Tooltip, Space } from 'ant-design-vue'; |
| | | import { useModal } from '/@/components/Modal'; |
| | | import { useModal } from '@/components/Modal'; |
| | | import { uploadContainerProps } from './props'; |
| | | import { omit } from 'lodash-es'; |
| | | import { useI18n } from '/@/hooks/web/useI18n'; |
| | | import { isArray } from '/@/utils/is'; |
| | | import UploadModal from './UploadModal.vue'; |
| | | import UploadPreviewModal from './UploadPreviewModal.vue'; |
| | | import { useI18n } from '@/hooks/web/useI18n'; |
| | | import { isArray, isObject, isString } from '@/utils/is'; |
| | | import UploadModal from './components/UploadModal.vue'; |
| | | import UploadPreviewModal from './components/UploadPreviewModal.vue'; |
| | | import { BaseFileItem } from './types/typing'; |
| | | import { buildUUID } from '@/utils/uuid'; |
| | | defineOptions({ name: 'BasicUpload' }); |
| | | |
| | | export default defineComponent({ |
| | | name: 'BasicUpload', |
| | | components: { UploadModal, Space, UploadPreviewModal, Icon, Tooltip }, |
| | | props: uploadContainerProps, |
| | | emits: ['change', 'delete', 'preview-delete', 'update:value'], |
| | | const props = defineProps(uploadContainerProps); |
| | | |
| | | setup(props, { emit, attrs }) { |
| | | const { t } = useI18n(); |
| | | // 上传modal |
| | | const [registerUploadModal, { openModal: openUploadModal }] = useModal(); |
| | | const emit = defineEmits(['change', 'delete', 'preview-delete', 'update:value']); |
| | | |
| | | // 预览modal |
| | | const [registerPreviewModal, { openModal: openPreviewModal }] = useModal(); |
| | | const attrs = useAttrs(); |
| | | const { t } = useI18n(); |
| | | // 上传modal |
| | | const [registerUploadModal, { openModal: openUploadModal }] = useModal(); |
| | | |
| | | const fileList = ref<string[]>([]); |
| | | // 预览modal |
| | | const [registerPreviewModal, { openModal: openPreviewModal }] = useModal(); |
| | | |
| | | const showPreview = computed(() => { |
| | | const { emptyHidePreview } = props; |
| | | if (!emptyHidePreview) return true; |
| | | return emptyHidePreview ? fileList.value.length > 0 : true; |
| | | }); |
| | | const fileList = ref<BaseFileItem[] | any[]>([]); |
| | | |
| | | const bindValue = computed(() => { |
| | | const value = { ...attrs, ...props }; |
| | | return omit(value, 'onChange'); |
| | | }); |
| | | |
| | | watch( |
| | | () => props.value, |
| | | (value = []) => { |
| | | fileList.value = isArray(value) ? value : []; |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | // 上传modal保存操作 |
| | | function handleChange(urls: string[]) { |
| | | fileList.value = [...unref(fileList), ...(urls || [])]; |
| | | emit('update:value', fileList.value); |
| | | emit('change', fileList.value); |
| | | } |
| | | |
| | | // 预览modal保存操作 |
| | | function handlePreviewChange(urls: string[]) { |
| | | fileList.value = [...(urls || [])]; |
| | | emit('update:value', fileList.value); |
| | | emit('change', fileList.value); |
| | | } |
| | | |
| | | function handleDelete(record: Recordable<any>) { |
| | | emit('delete', record); |
| | | } |
| | | |
| | | function handlePreviewDelete(url: string) { |
| | | emit('preview-delete', url); |
| | | } |
| | | |
| | | return { |
| | | registerUploadModal, |
| | | openUploadModal, |
| | | handleChange, |
| | | handlePreviewChange, |
| | | registerPreviewModal, |
| | | openPreviewModal, |
| | | fileList, |
| | | showPreview, |
| | | bindValue, |
| | | handleDelete, |
| | | handlePreviewDelete, |
| | | t, |
| | | }; |
| | | }, |
| | | const showPreview = computed(() => { |
| | | const { emptyHidePreview } = props; |
| | | if (!emptyHidePreview) return true; |
| | | return emptyHidePreview ? fileList.value.length > 0 : true; |
| | | }); |
| | | |
| | | const bindValue = computed(() => { |
| | | const value = { ...attrs, ...props }; |
| | | return omit(value, 'onChange'); |
| | | }); |
| | | |
| | | const isFirstRender = ref<boolean>(true) |
| | | |
| | | function getValue(valueKey="url") { |
| | | const list = (fileList.value || []).map((item: any) => { |
| | | return item[valueKey]; |
| | | }); |
| | | return list; |
| | | } |
| | | function genFileListByUrls(urls: string[]) { |
| | | const list = urls.map((e) => { |
| | | return { |
| | | uid: buildUUID(), |
| | | url: e, |
| | | }; |
| | | }); |
| | | return list; |
| | | } |
| | | watch( |
| | | () => props.value, |
| | | (v = []) => { |
| | | let values: string[] = []; |
| | | if (v) { |
| | | if (isArray(v)) { |
| | | values = v; |
| | | } else if (typeof v == 'string') { |
| | | values.push(v); |
| | | } |
| | | fileList.value = values.map((item,i) => { |
| | | if (item && isString(item)) { |
| | | return { |
| | | uid: buildUUID(), |
| | | url: item, |
| | | }; |
| | | } else if (item && isObject(item)) { |
| | | return item; |
| | | } else { |
| | | return; |
| | | } |
| | | }) as any; |
| | | } |
| | | emit('update:value', values); |
| | | if(!isFirstRender.value){ |
| | | emit('change', values); |
| | | isFirstRender.value = false |
| | | } |
| | | }, |
| | | { |
| | | immediate: true, |
| | | deep: true, |
| | | }, |
| | | ); |
| | | |
| | | // 上传modal保存操作 |
| | | function handleChange(urls: string[],valueKey:string) { |
| | | fileList.value = [...unref(fileList), ...(genFileListByUrls(urls) || [])]; |
| | | const values = getValue(valueKey); |
| | | emit('update:value', values); |
| | | emit('change', values); |
| | | } |
| | | |
| | | // 预览modal保存操作 |
| | | function handlePreviewChange(fileItems: string[],valueKey:string) { |
| | | fileList.value = [...(fileItems || [])]; |
| | | const values = getValue(valueKey); |
| | | emit('update:value', values); |
| | | emit('change', values); |
| | | } |
| | | |
| | | function handleDelete(record: Recordable<any>) { |
| | | emit('delete', record); |
| | | } |
| | | |
| | | function handlePreviewDelete(url: string) { |
| | | emit('preview-delete', url); |
| | | } |
| | | </script> |