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 {