提交 | 用户 | 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> |