From 1ec1bc34eb061dfacb84f501af20ea284192afd9 Mon Sep 17 00:00:00 2001 From: DXC Date: Fri, 15 May 2026 14:19:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20PC=20=E7=AB=AF?= =?UTF-8?q?=E7=B2=98=E8=B4=B4=E5=9B=BE=E7=89=87=E4=B8=8A=E4=BC=A0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=88hover=20=E5=8C=BA=E5=9F=9F=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=20+=20=E7=BD=91=E9=A1=B5=E5=9B=BE=E7=89=87=E9=93=BE=E6=8E=A5?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=A1=AB=E5=85=A5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- inventory-web/src/hooks/usePasteUpload.ts | 81 +++++++++++++++++++++++ inventory-web/src/views/material/list.vue | 19 +++++- 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 inventory-web/src/hooks/usePasteUpload.ts diff --git a/inventory-web/src/hooks/usePasteUpload.ts b/inventory-web/src/hooks/usePasteUpload.ts new file mode 100644 index 0000000..ea3f694 --- /dev/null +++ b/inventory-web/src/hooks/usePasteUpload.ts @@ -0,0 +1,81 @@ +import { onMounted, onUnmounted, ref } from 'vue' +import { ElMessage } from 'element-plus' + +export function usePasteUpload( + customUpload: Function, + targetField: string, + containerSelector: string, + onLinkFound?: (link: string, field: string) => void +) { + const isHovering = ref(false) + + const handleMouseMove = (event: MouseEvent) => { + const target = event.target as Element + if (!target) return + const isInsideTarget = !!target.closest(containerSelector) + if (isInsideTarget !== isHovering.value) { + isHovering.value = isInsideTarget + } + } + + const handleGlobalPaste = (event: ClipboardEvent) => { + if (!isHovering.value) return + + const activeElement = document.activeElement + const activeTag = activeElement?.tagName.toLowerCase() + if (activeTag === 'input' || activeTag === 'textarea') return + + const clipboardData = event.clipboardData + if (!clipboardData) return + + // 1. 优先获取真实文件(本地截图/复制文件) + let imageFile: File | null = null + for (let i = 0; i < clipboardData.items.length; i++) { + if (clipboardData.items[i].type.indexOf('image') !== -1) { + const rawFile = clipboardData.items[i].getAsFile() + if (rawFile) { + const extension = rawFile.type.split('/')[1] || 'png' + const fileName = `paste_${targetField}_${new Date().getTime()}.${extension}` + imageFile = new File([rawFile], fileName, { type: rawFile.type }) + break + } + } + } + + if (imageFile) { + event.preventDefault() + customUpload({ file: imageFile, onSuccess: () => {}, onError: () => {} }, targetField) + return + } + + // 2. 没有真实文件时,解析 HTML 或文本里的图片 URL(网页复制场景) + const htmlData = clipboardData.getData('text/html') + const textData = clipboardData.getData('text/plain') + + let imgUrl = '' + if (htmlData) { + const match = htmlData.match(/]+src="([^">]+)"/) + if (match && match[1]) imgUrl = match[1] + } + if (!imgUrl && textData && textData.startsWith('http')) { + imgUrl = textData + } + + if (imgUrl && onLinkFound) { + event.preventDefault() + ElMessage.success('检测到网页图片,已自动填入外部链接') + onLinkFound(imgUrl, targetField) + } else if (!imgUrl) { + ElMessage.warning('剪贴板中未检测到有效图片或链接') + } + } + + onMounted(() => { + document.addEventListener('mousemove', handleMouseMove) + document.addEventListener('paste', handleGlobalPaste) + }) + onUnmounted(() => { + document.removeEventListener('mousemove', handleMouseMove) + document.removeEventListener('paste', handleGlobalPaste) + }) +} \ No newline at end of file diff --git a/inventory-web/src/views/material/list.vue b/inventory-web/src/views/material/list.vue index 6f00d5e..eecb890 100644 --- a/inventory-web/src/views/material/list.vue +++ b/inventory-web/src/views/material/list.vue @@ -457,7 +457,7 @@ -
+
-
+
{ + imageExternalUrl.value = link +} +usePasteUpload(customUpload, 'generalImage', '#upload-generalImage', handlePasteLink) +usePasteUpload(customUpload, 'generalManual', '#upload-generalManual', handlePasteLink) + const handleRemoveImage = async (uploadFile: any, targetField: 'generalImage' | 'generalManual') => { const fileName = uploadFile.name || uploadFile.url?.split('/').pop() || '此文件' try {