From d6392781825520a26439bc7ac31df721960138a1 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Sun, 7 Jun 2026 17:19:53 +0800 Subject: [PATCH] =?UTF-8?q?fix(overlay):=20=E4=BF=AE=E5=A4=8D=E6=89=8B?= =?UTF-8?q?=E6=9C=BA=E7=AB=AF=E5=9B=BE=E7=89=87/=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E9=80=89=E6=8B=A9=E5=85=BC=E5=AE=B9=E6=80=A7?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 local-files 事件类型由 FileList 改为 File[],避免 WebView 中 FileList 在 input 清空后失效 - 屏蔽文件选择器关闭后 500ms 内的 backdrop click,防止 touch 穿透误关 overlay - 延迟 200ms 清空 input value,避免国产手机 WebView 异步填充 files 被截断 --- static/src/components/overlay/ImagePicker.vue | 26 ++++++++++++++----- static/src/components/overlay/VideoPicker.vue | 15 ++++++++--- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/static/src/components/overlay/ImagePicker.vue b/static/src/components/overlay/ImagePicker.vue index 59520b5..4bab66b 100644 --- a/static/src/components/overlay/ImagePicker.vue +++ b/static/src/components/overlay/ImagePicker.vue @@ -79,12 +79,14 @@ const props = withDefaults( const emit = defineEmits<{ (e: 'close'): void; (e: 'confirm', list: string[]): void; - (e: 'local-files', files: FileList | null): void; + (e: 'local-files', files: File[] | null): void; }>(); const selectedSet = ref>(new Set(props.initialSelected || [])); const localInput = ref(null); +let ignoreBackdropClickUntil = 0; + watch( () => props.initialSelected, (val) => { @@ -106,25 +108,35 @@ const toggle = (path: string) => { selectedSet.value = set; }; -const close = () => emit('close'); +const close = () => { + if (Date.now() < ignoreBackdropClickUntil) return; + emit('close'); +}; const confirm = () => emit('confirm', Array.from(selectedSet.value)); const triggerLocal = () => { if (props.uploading) return; + // 屏蔽接下来 500ms 内的 backdrop click,防止系统文件选择器关闭后的 touch 穿透误关 overlay + ignoreBackdropClickUntil = Date.now() + 500; localInput.value?.click(); }; const onLocalChange = (event: Event) => { const target = event.target as HTMLInputElement; - const files = target?.files || null; + const rawFiles = target?.files; + // 某些 WebView(尤其国产手机)在 input value 被清空后 FileList 会失效,先深拷贝 + const files = rawFiles && rawFiles.length ? Array.from(rawFiles) : null; if (!files || files.length === 0) { console.warn('[ImagePicker] change fired but files empty — likely WebView compat issue'); + emit('local-files', null); + } else { + emit('local-files', files); } - emit('local-files', files); - if (target) { - target.value = ''; - } + // 延迟清空:国产手机 WebView 中 files 填充可能是异步的,立即清空会导致 files 被截断 + setTimeout(() => { + if (target) target.value = ''; + }, 200); }; const previewUrl = (path: string) => `/api/gui/files/download?path=${encodeURIComponent(path)}`; diff --git a/static/src/components/overlay/VideoPicker.vue b/static/src/components/overlay/VideoPicker.vue index 1013c0c..40bf1ed 100644 --- a/static/src/components/overlay/VideoPicker.vue +++ b/static/src/components/overlay/VideoPicker.vue @@ -81,12 +81,14 @@ const props = withDefaults( const emit = defineEmits<{ (e: 'close'): void; (e: 'confirm', list: string[]): void; - (e: 'local-files', files: FileList | null): void; + (e: 'local-files', files: File[] | null): void; }>(); const selectedSet = ref>(new Set(props.initialSelected || [])); const localInput = ref(null); +let ignoreBackdropClickUntil = 0; + watch( () => props.initialSelected, (val) => { @@ -108,18 +110,25 @@ const toggle = (path: string) => { selectedSet.value = set; }; -const close = () => emit('close'); +const close = () => { + if (Date.now() < ignoreBackdropClickUntil) return; + emit('close'); +}; const confirm = () => emit('confirm', Array.from(selectedSet.value)); const triggerLocal = () => { if (props.uploading) return; + // 屏蔽接下来 500ms 内的 backdrop click,防止系统文件选择器关闭后的 touch 穿透误关 overlay + ignoreBackdropClickUntil = Date.now() + 500; localInput.value?.click(); }; const onLocalChange = (event: Event) => { const target = event.target as HTMLInputElement; - const files = target?.files || null; + const rawFiles = target?.files; + // 某些 WebView(尤其国产手机)在 input value 被清空后 FileList 会失效,先深拷贝 + const files = rawFiles && rawFiles.length ? Array.from(rawFiles) : null; if (!files || files.length === 0) { console.warn('[VideoPicker] change fired but files empty — likely WebView compat issue'); }