diff --git a/src/pages/ChatPage.scss b/src/pages/ChatPage.scss index e9b6174..9d51e02 100644 --- a/src/pages/ChatPage.scss +++ b/src/pages/ChatPage.scss @@ -2016,12 +2016,43 @@ text-align: right; color: var(--text-primary); word-break: break-all; + user-select: text; &.highlight { color: var(--primary); font-weight: 600; } } + + .copy-btn { + display: flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + padding: 0; + border: none; + border-radius: 4px; + background: transparent; + color: var(--text-tertiary); + cursor: pointer; + flex-shrink: 0; + opacity: 0; + transition: opacity 0.15s, color 0.15s, background 0.15s; + + &:hover { + background: var(--bg-secondary); + color: var(--text-primary); + } + + svg { + color: inherit; + } + } + + &:hover .copy-btn { + opacity: 1; + } } .table-list { diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx index 63d127c..94e96c5 100644 --- a/src/pages/ChatPage.tsx +++ b/src/pages/ChatPage.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react' -import { Search, MessageSquare, AlertCircle, Loader2, RefreshCw, X, ChevronDown, Info, Calendar, Database, Hash, Play, Pause, Image as ImageIcon, Link, Mic, CheckCircle, XCircle } from 'lucide-react' +import { Search, MessageSquare, AlertCircle, Loader2, RefreshCw, X, ChevronDown, Info, Calendar, Database, Hash, Play, Pause, Image as ImageIcon, Link, Mic, CheckCircle, XCircle, Copy, Check } from 'lucide-react' import { createPortal } from 'react-dom' import { useChatStore } from '../stores/chatStore' import type { ChatSession, Message } from '../types/models' @@ -168,6 +168,7 @@ function ChatPage(_props: ChatPageProps) { const [showDetailPanel, setShowDetailPanel] = useState(false) const [sessionDetail, setSessionDetail] = useState(null) const [isLoadingDetail, setIsLoadingDetail] = useState(false) + const [copiedField, setCopiedField] = useState(null) const [highlightedMessageKeys, setHighlightedMessageKeys] = useState([]) const [isRefreshingSessions, setIsRefreshingSessions] = useState(false) const [hasInitialMessages, setHasInitialMessages] = useState(false) @@ -243,6 +244,25 @@ function ChatPage(_props: ChatPageProps) { setShowDetailPanel(!showDetailPanel) }, [showDetailPanel, currentSessionId, loadSessionDetail]) + // 复制字段值到剪贴板 + const handleCopyField = useCallback(async (text: string, field: string) => { + try { + await navigator.clipboard.writeText(text) + setCopiedField(field) + setTimeout(() => setCopiedField(null), 1500) + } catch { + // fallback + const textarea = document.createElement('textarea') + textarea.value = text + document.body.appendChild(textarea) + textarea.select() + document.execCommand('copy') + document.body.removeChild(textarea) + setCopiedField(field) + setTimeout(() => setCopiedField(null), 1500) + } + }, []) + // 连接数据库 const connect = useCallback(async () => { setConnecting(true) @@ -1601,23 +1621,35 @@ function ChatPage(_props: ChatPageProps) { 微信ID {sessionDetail.wxid} + {sessionDetail.remark && (
备注 {sessionDetail.remark} +
)} {sessionDetail.nickName && (
昵称 {sessionDetail.nickName} +
)} {sessionDetail.alias && (
微信号 {sessionDetail.alias} +
)}