Sanakey
6 天以前 cb165187ddcf5d9cfd8aad97a2868d0343b14bd9
提交 | 用户 | age
661db0 1 <template>
V 2   <div>
3fcfac 3     <Space>
69a6e9 4       <a-button
E 5         type="primary"
6         @click="openUploadModal"
7         preIcon="carbon:cloud-upload"
8         :disabled="disabled"
9       >
962f90 10         {{ t('component.upload.upload') }}
661db0 11       </a-button>
V 12       <Tooltip placement="bottom" v-if="showPreview">
13         <template #title>
962f90 14           {{ t('component.upload.uploaded') }}
3f6920 15           <template v-if="fileList.length">
V 16             {{ fileList.length }}
9edc28 17           </template>
661db0 18         </template>
V 19         <a-button @click="openPreviewModal">
5dc822 20           <Icon icon="bi:eye" />
3f6920 21           <template v-if="fileList.length && showPreviewNumber">
V 22             {{ fileList.length }}
661db0 23           </template>
V 24         </a-button>
25       </Tooltip>
3fcfac 26     </Space>
91e004 27     <UploadModal
V 28       v-bind="bindValue"
3f6920 29       :previewFileList="fileList"
beed7f 30       :fileListOpenDrag="fileListOpenDrag"
B 31       :fileListDragOptions="fileListDragOptions"
91e004 32       @register="registerUploadModal"
V 33       @change="handleChange"
3f6920 34       @delete="handleDelete"
91e004 35     />
661db0 36
V 37     <UploadPreviewModal
3f6920 38       :value="fileList"
29ef0d 39       :max-number="bindValue.maxNumber"
661db0 40       @register="registerPreviewModal"
V 41       @list-change="handlePreviewChange"
49e72a 42       @delete="handlePreviewDelete"
87541d 43       :preview-columns="props.previewColumns"
X 44       :before-preview-data="props.beforePreviewData"
661db0 45     />
V 46   </div>
47 </template>
bab28a 48 <script lang="ts" setup>
X 49   import { ref, watch, unref, computed, useAttrs } from 'vue';
762e5d 50   import { Recordable } from '@vben/types';
V 51   import Icon from '@/components/Icon/Icon.vue';
3fcfac 52   import { Tooltip, Space } from 'ant-design-vue';
bab28a 53   import { useModal } from '@/components/Modal';
661db0 54   import { uploadContainerProps } from './props';
V 55   import { omit } from 'lodash-es';
bab28a 56   import { useI18n } from '@/hooks/web/useI18n';
d9cdf3 57   import { isArray, isObject, isString } from '@/utils/is';
dccc8f 58   import UploadModal from './components/UploadModal.vue';
Z 59   import UploadPreviewModal from './components/UploadPreviewModal.vue';
d9cdf3 60   import { BaseFileItem } from './types/typing';
E 61   import { buildUUID } from '@/utils/uuid';
baf406 62
bab28a 63   defineOptions({ name: 'BasicUpload' });
9edc28 64
bab28a 65   const props = defineProps(uploadContainerProps);
661db0 66
bab28a 67   const emit = defineEmits(['change', 'delete', 'preview-delete', 'update:value']);
661db0 68
bab28a 69   const attrs = useAttrs();
X 70   const { t } = useI18n();
71   // 上传modal
72   const [registerUploadModal, { openModal: openUploadModal }] = useModal();
661db0 73
bab28a 74   //   预览modal
X 75   const [registerPreviewModal, { openModal: openPreviewModal }] = useModal();
661db0 76
d9cdf3 77   const fileList = ref<BaseFileItem[] | any[]>([]);
661db0 78
bab28a 79   const showPreview = computed(() => {
X 80     const { emptyHidePreview } = props;
81     if (!emptyHidePreview) return true;
82     return emptyHidePreview ? fileList.value.length > 0 : true;
661db0 83   });
bab28a 84
X 85   const bindValue = computed(() => {
86     const value = { ...attrs, ...props };
87     return omit(value, 'onChange');
88   });
cca7f5 89
baf406 90   const isFirstRender = ref<boolean>(true);
cca7f5 91
baf406 92   function getValue(valueKey = 'url') {
d9cdf3 93     const list = (fileList.value || []).map((item: any) => {
E 94       return item[valueKey];
95     });
96     return list;
97   }
98   function genFileListByUrls(urls: string[]) {
99     const list = urls.map((e) => {
100       return {
101         uid: buildUUID(),
102         url: e,
103       };
104     });
105     return list;
106   }
bab28a 107   watch(
X 108     () => props.value,
d9cdf3 109     (v = []) => {
E 110       let values: string[] = [];
111       if (v) {
112         if (isArray(v)) {
113           values = v;
114         } else if (typeof v == 'string') {
115           values.push(v);
116         }
baf406 117         fileList.value = values.map((item) => {
d9cdf3 118           if (item && isString(item)) {
E 119             return {
120               uid: buildUUID(),
121               url: item,
122             };
123           } else if (item && isObject(item)) {
124             return item;
125           } else {
126             return;
127           }
128         }) as any;
129       }
130       emit('update:value', values);
baf406 131       if (!isFirstRender.value) {
cca7f5 132         emit('change', values);
baf406 133         isFirstRender.value = false;
cca7f5 134       }
bab28a 135     },
baf406 136     {
C 137       immediate: true,
cca7f5 138       deep: true,
E 139     },
bab28a 140   );
X 141
142   // 上传modal保存操作
baf406 143   function handleChange(urls: string[], valueKey: string) {
d9cdf3 144     fileList.value = [...unref(fileList), ...(genFileListByUrls(urls) || [])];
E 145     const values = getValue(valueKey);
146     emit('update:value', values);
147     emit('change', values);
bab28a 148   }
X 149
150   // 预览modal保存操作
baf406 151   function handlePreviewChange(fileItems: string[], valueKey: string) {
d9cdf3 152     fileList.value = [...(fileItems || [])];
E 153     const values = getValue(valueKey);
154     emit('update:value', values);
155     emit('change', values);
bab28a 156   }
X 157
158   function handleDelete(record: Recordable<any>) {
159     emit('delete', record);
160   }
161
162   function handlePreviewDelete(url: string) {
163     emit('preview-delete', url);
164   }
cb1651 165
S 166   // 暴露openUploadModal 供父组件使用
167   defineExpose({
168     openUploadModal,
169   });
661db0 170 </script>