From 76afe5f433cc8b84d44aa8552fc11d835d4b4a5e Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Sat, 16 May 2026 11:08:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(ai-chat):=20=E6=94=AF=E6=8C=81=E9=95=BF?= =?UTF-8?q?=E6=8C=89=E5=A4=8D=E5=88=B6=E6=B6=88=E6=81=AF=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages_tool/ai-chat/ai-chat-message.vue | 150 ++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 5 deletions(-) diff --git a/pages_tool/ai-chat/ai-chat-message.vue b/pages_tool/ai-chat/ai-chat-message.vue index 41dc5e9..a62a8ce 100644 --- a/pages_tool/ai-chat/ai-chat-message.vue +++ b/pages_tool/ai-chat/ai-chat-message.vue @@ -39,8 +39,13 @@ {{ formatTime(message.timestamp) }} - - {{ message.content }} + + {{ message.content }} @@ -63,7 +68,12 @@ 智能助手 {{ formatTime(message.timestamp) }} - + @@ -512,7 +522,11 @@ export default { lastScrollTop: 0, historyOffset: 0, isFetchingHistory: false, - keyboardHeight: 0 + keyboardHeight: 0, + + // 手动长按检测相关(touch 计时器) + _longPressTimer: null, + _longPressMessage: null } }, computed: { @@ -1755,7 +1769,126 @@ _handleStreamError(msg) { this.$emit('action-click', { action, message }) }, - + + // 长按消息→直接复制 + onMessageLongPress(message) { + // loading 消息不允许操作 + if (message.type === 'loading') return + + // #ifdef MP-WEIXIN + // 微信小程序:震动反馈提升手感(小米等 Android 设备也可用) + try { + wx.vibrateShort({ type: 'medium' }) + } catch (e) { /* 不支持震动的设备忽略 */ } + // #endif + + this.copyMessage(message) + }, + + // 手动长按检测(touch 事件方案,兼容所有平台) + // 在 H5 desktop 上用 @contextmenu 触发, + // 在 H5 mobile / 小米微信小程序等场景靠 touch 计时器兜底 + onBubbleTouchStart(event, message) { + // 单指长按才触发,忽略多点触控 + if (event.touches && event.touches.length > 1) return + this._longPressMessage = message + this._longPressTimer = setTimeout(() => { + this._longPressTimer = null + this.onMessageLongPress(message) + }, 500) // 和系统长按接近的 500ms + }, + onBubbleTouchMove() { + // 手指移动(滚动列表)→ 取消长按 + if (this._longPressTimer) { + clearTimeout(this._longPressTimer) + this._longPressTimer = null + } + this._longPressMessage = null + }, + onBubbleTouchEnd() { + // 手指提前松开 → 取消长按 + if (this._longPressTimer) { + clearTimeout(this._longPressTimer) + this._longPressTimer = null + } + this._longPressMessage = null + }, + + // 复制消息内容到剪贴板(兼容 H5 / 微信小程序) + copyMessage(message) { + let copyText = message.content || '' + if (!copyText && message.type === 'text') { + copyText = message.content || '' + } + if (!copyText) { + uni.showToast({ title: '无可复制的内容', icon: 'none' }) + return + } + + // #ifdef H5 + // H5:检测是否有局部文本被选中,有则复制选区文本,无则复制全文 + const selection = window.getSelection() + const selectedText = selection && selection.toString().trim() + const finalText = selectedText || copyText + + // H5 优先使用 Clipboard API,降级使用 document.execCommand + try { + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(finalText).then(() => { + uni.showToast({ title: selectedText ? '已复制选中内容' : '已复制', icon: 'success' }) + }).catch(() => { + this._fallbackCopyH5(finalText) + }) + } else { + this._fallbackCopyH5(finalText) + } + } catch (e) { + this._fallbackCopyH5(finalText) + } + // #endif + + // #ifdef MP-WEIXIN + // 微信小程序专用(含小米等 Android 兼容) + console.log('[AI Chat] 开始复制, 内容长度:', copyText.length, '内容前50字:', copyText.substring(0, 50)) + uni.setClipboardData({ + data: copyText, + success: () => { + console.log('[AI Chat] 复制成功') + uni.showToast({ title: '已复制', icon: 'success' }) + }, + fail: (err) => { + console.error('[AI Chat] 复制失败, 详细错误:', JSON.stringify(err)) + console.error('[AI Chat] 复制失败 errMsg:', err.errMsg || err.message || '无错误消息') + uni.showToast({ title: '复制失败: ' + (err.errMsg || '未知错误'), icon: 'none', duration: 3000 }) + } + }) + // #endif + }, + + // H5 降级复制方案(document.execCommand + textarea) + _fallbackCopyH5(text) { + try { + const textarea = document.createElement('textarea') + textarea.value = text + textarea.style.position = 'fixed' + textarea.style.left = '-9999px' + textarea.style.top = '-9999px' + textarea.style.opacity = '0' + document.body.appendChild(textarea) + textarea.select() + textarea.setSelectionRange(0, text.length) + const success = document.execCommand('copy') + document.body.removeChild(textarea) + if (success) { + uni.showToast({ title: '已复制', icon: 'success' }) + } else { + uni.showToast({ title: '复制失败', icon: 'none' }) + } + } catch (e) { + uni.showToast({ title: '复制失败', icon: 'none' }) + } + }, + // 重试消息 async retryMessage(message) { // 找到对应的用户消息 @@ -4066,5 +4199,12 @@ $radius-lg: 36rpx; } } } + + // H5 下允许 rich-text 内容文本选择(鼠标拖选复制) + .text-content, + .markdown-body { + user-select: text; + -webkit-user-select: text; + } }