From f7d5040b0243fe1a4d99b71c11067714436de45f Mon Sep 17 00:00:00 2001 From: kuaifan Date: Tue, 20 Jan 2026 14:45:38 +0000 Subject: [PATCH] =?UTF-8?q?feat(ai-assistant):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8B=96=E6=94=BE=E5=92=8C=E7=B2=98=E8=B4=B4=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增拖放上传:可将图片拖放到对话窗口任意位置 - 新增粘贴上传:在输入框中可直接粘贴剪贴板图片 - 提取 handleImageFiles 通用方法供多种上传方式复用 - 添加拖放时的视觉反馈(虚线边框 + 提示遮罩) - 使用计数器方式正确处理嵌套元素和拖出窗口的情况 Co-Authored-By: Claude Opus 4.5 --- .../js/components/AIAssistant/index.vue | 131 +++++++++++++++++- 1 file changed, 125 insertions(+), 6 deletions(-) diff --git a/resources/assets/js/components/AIAssistant/index.vue b/resources/assets/js/components/AIAssistant/index.vue index 08433fc96..7fb0a971e 100644 --- a/resources/assets/js/components/AIAssistant/index.vue +++ b/resources/assets/js/components/AIAssistant/index.vue @@ -47,7 +47,20 @@ -
+
+ +
+
+ + {{ $L('松开以上传图片') }} +
+
+ @compositionend.native="isComposing = false" + @paste.native="onPaste" /> 0) { + const imageFiles = Array.from(files).filter(f => f.type.startsWith('image/')); + await this.handleImageFiles(imageFiles); + } + }, + + /** + * 处理粘贴图片 + */ + async onPaste(event) { + const items = event.clipboardData?.items; + if (!items) { + return; + } + const imageFiles = []; + for (const item of items) { + if (item.type.startsWith('image/')) { + const file = item.getAsFile(); + if (file) { + imageFiles.push(file); + } + } + } + if (imageFiles.length > 0) { + event.preventDefault(); + await this.handleImageFiles(imageFiles); + } }, /** @@ -2098,6 +2177,46 @@ export default { .ai-assistant-content { display: flex; flex-direction: column; + position: relative; + + &.ai-assistant-content-dragging { + &::before { + content: ''; + position: absolute; + inset: 8px; + border: 2px dashed #2d8cf0; + border-radius: 8px; + background-color: rgba(45, 140, 240, 0.05); + pointer-events: none; + z-index: 10; + } + } + + .ai-assistant-drop-overlay { + position: absolute; + inset: 8px; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(255, 255, 255, 0.9); + border-radius: 8px; + z-index: 11; + pointer-events: none; + } + + .ai-assistant-drop-hint { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + color: #2d8cf0; + .taskfont { + font-size: 32px; + } + span { + font-size: 14px; + } + } .ai-assistant-welcome, .ai-assistant-output {