feat(FileUploaderField): 为只读模式文件上传字段添加图片预览功能
新增图片缩略图展示,集成van-image-preview全屏预览组件,新增文件扩展名过滤逻辑识别可预览图片,完善只读场景交互体验
Showing
1 changed file
with
64 additions
and
9 deletions
| ... | @@ -55,17 +55,22 @@ | ... | @@ -55,17 +55,22 @@ |
| 55 | <van-divider /> | 55 | <van-divider /> |
| 56 | </div> | 56 | </div> |
| 57 | <div v-else style="padding: 1rem;"> | 57 | <div v-else style="padding: 1rem;"> |
| 58 | - <!-- <a | 58 | + <div v-if="previewImageList.length" class="readonly-image-list"> |
| 59 | - v-for="(item, index) in default_file" :key="index" | 59 | + <van-image |
| 60 | - :href="item.url" | 60 | + v-for="(item, index) in previewImageList" |
| 61 | - :download="item.name" | 61 | + :key="item.url || index" |
| 62 | - style="color: #000; font-size: 0.9rem; text-decoration: underline; margin-right: 0.5rem;" | 62 | + width="80" |
| 63 | - > | 63 | + height="80" |
| 64 | - {{ item.name }} | 64 | + fit="contain" |
| 65 | - </a> --> | 65 | + position="center" |
| 66 | + :src="item.url" | ||
| 67 | + style="margin-right: 0.5rem; margin-block-end: 0.25rem; border: 1px solid #eee; padding: 0.5rem;" | ||
| 68 | + @click="onPreviewImage(index)" | ||
| 69 | + /> | ||
| 70 | + </div> | ||
| 66 | <a | 71 | <a |
| 67 | @click="downloadFile(item)" | 72 | @click="downloadFile(item)" |
| 68 | - v-for="(item, index) in default_file" :key="index" | 73 | + v-for="(item, index) in readonlyFileList" :key="`${item.url || item.name}-${index}`" |
| 69 | style="color: #000; font-size: 0.9rem; text-decoration: underline; margin-right: 0.5rem; cursor:pointer;" | 74 | style="color: #000; font-size: 0.9rem; text-decoration: underline; margin-right: 0.5rem; cursor:pointer;" |
| 70 | > | 75 | > |
| 71 | {{ item.name }} | 76 | {{ item.name }} |
| ... | @@ -79,6 +84,15 @@ | ... | @@ -79,6 +84,15 @@ |
| 79 | <van-loading vertical color="#FFFFFF">上传中...</van-loading> | 84 | <van-loading vertical color="#FFFFFF">上传中...</van-loading> |
| 80 | </div> | 85 | </div> |
| 81 | </van-overlay> | 86 | </van-overlay> |
| 87 | + | ||
| 88 | + <van-image-preview | ||
| 89 | + v-model:show="showImagePreview" | ||
| 90 | + :images="previewImageUrls" | ||
| 91 | + :start-position="previewImageIndex" | ||
| 92 | + @change="onImagePreviewChange" | ||
| 93 | + > | ||
| 94 | + <template #index>第{{ previewImageIndex + 1 }}张</template> | ||
| 95 | + </van-image-preview> | ||
| 82 | </template> | 96 | </template> |
| 83 | 97 | ||
| 84 | <script setup> | 98 | <script setup> |
| ... | @@ -112,6 +126,38 @@ const ReadonlyShow = computed(() => { | ... | @@ -112,6 +126,38 @@ const ReadonlyShow = computed(() => { |
| 112 | const emit = defineEmits(["active"]); | 126 | const emit = defineEmits(["active"]); |
| 113 | const show_empty = ref(false); | 127 | const show_empty = ref(false); |
| 114 | const default_file = ref(props.item.component_props.default); | 128 | const default_file = ref(props.item.component_props.default); |
| 129 | +const previewImageIndex = ref(0); | ||
| 130 | +const showImagePreview = ref(false); | ||
| 131 | + | ||
| 132 | +// TAG:详情态兼容历史文件数据,只靠文件名或链接后缀判断是否可按图片预览 | ||
| 133 | +const imageExtensionList = ["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "tif", "tiff"]; | ||
| 134 | + | ||
| 135 | +const getFileExtension = (value = "") => { | ||
| 136 | + const cleanValue = value.split("?")[0].split("#")[0]; | ||
| 137 | + const extension = cleanValue.split(".").pop(); | ||
| 138 | + return extension ? extension.toLowerCase() : ""; | ||
| 139 | +}; | ||
| 140 | + | ||
| 141 | +const isImageFile = (file = {}) => { | ||
| 142 | + const nameExtension = getFileExtension(file.name || ""); | ||
| 143 | + const urlExtension = getFileExtension(file.url || ""); | ||
| 144 | + return imageExtensionList.includes(nameExtension) || imageExtensionList.includes(urlExtension); | ||
| 145 | +}; | ||
| 146 | + | ||
| 147 | +const readonlyFileList = computed(() => { | ||
| 148 | + if (!Array.isArray(default_file.value)) { | ||
| 149 | + return []; | ||
| 150 | + } | ||
| 151 | + return default_file.value.filter((item) => item?.url); | ||
| 152 | +}); | ||
| 153 | + | ||
| 154 | +const previewImageList = computed(() => { | ||
| 155 | + return readonlyFileList.value.filter((item) => isImageFile(item)); | ||
| 156 | +}); | ||
| 157 | + | ||
| 158 | +const previewImageUrls = computed(() => { | ||
| 159 | + return previewImageList.value.map((item) => item.url); | ||
| 160 | +}); | ||
| 115 | 161 | ||
| 116 | onMounted(() => { | 162 | onMounted(() => { |
| 117 | // 非只读模式并且有默认值时 | 163 | // 非只读模式并且有默认值时 |
| ... | @@ -154,6 +200,15 @@ const downloadFile = (item) => { | ... | @@ -154,6 +200,15 @@ const downloadFile = (item) => { |
| 154 | } | 200 | } |
| 155 | } | 201 | } |
| 156 | 202 | ||
| 203 | +const onPreviewImage = (index) => { | ||
| 204 | + previewImageIndex.value = index; | ||
| 205 | + showImagePreview.value = true; | ||
| 206 | +}; | ||
| 207 | + | ||
| 208 | +const onImagePreviewChange = (index) => { | ||
| 209 | + previewImageIndex.value = index; | ||
| 210 | +}; | ||
| 211 | + | ||
| 157 | // TAG: 文件下载操作 | 212 | // TAG: 文件下载操作 |
| 158 | /** | 213 | /** |
| 159 | * 数据流下载 | 214 | * 数据流下载 | ... | ... |
-
Please register or login to post a comment