优化工作台输入与表情,并补充访客 IP 地区
- 输入框改为单层大尺寸 textarea,修复双层边框 - 新增表情选择器(工作台/Widget),插入 Unicode 表情 - 会话记录访客 IP/地区/UA,工作台顶栏与侧栏展示 - 去掉表情面板无用横向滚动条
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { useState, useEffect, useRef, useCallback, useMemo } from 'react'
|
||||
import {
|
||||
CloseOutlined, MessageOutlined, SmileOutlined, SendOutlined,
|
||||
CloseOutlined, MessageOutlined, SendOutlined,
|
||||
StarFilled, MinusOutlined, PictureOutlined, CustomerServiceOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import EmojiPicker, { insertAtCursor } from '@/components/common/EmojiPicker'
|
||||
|
||||
interface Message {
|
||||
id: number
|
||||
@@ -68,9 +69,22 @@ const VisitorChat = ({
|
||||
const typingTimerRef = useRef<number | null>(null)
|
||||
const chatEndRef = useRef<HTMLDivElement>(null)
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
const textInputRef = useRef<HTMLInputElement>(null)
|
||||
const socketRef = useRef<WebSocket | null>(null)
|
||||
const lastTypingAt = useRef(0)
|
||||
|
||||
const insertEmoji = (emoji: string) => {
|
||||
const { next, cursor } = insertAtCursor(textInputRef.current, input, emoji)
|
||||
setInput(next)
|
||||
if (agentsOnline) emitTyping()
|
||||
requestAnimationFrame(() => {
|
||||
const el = textInputRef.current
|
||||
if (!el) return
|
||||
el.focus()
|
||||
el.setSelectionRange(cursor, cursor)
|
||||
})
|
||||
}
|
||||
|
||||
const loadMessages = useCallback(async (sid?: number, token?: string) => {
|
||||
const s = sid || sessionId
|
||||
const visitorCredential = token || visitorToken || localStorage.getItem(tokenKey) || ''
|
||||
@@ -536,9 +550,12 @@ const VisitorChat = ({
|
||||
>
|
||||
<PictureOutlined className="text-base" />
|
||||
</button>
|
||||
<button type="button" className="w-8 h-8 rounded-md border-0 bg-transparent cursor-pointer flex items-center justify-center text-neutral-400 hover:bg-neutral-50" aria-label="表情">
|
||||
<SmileOutlined className="text-base" />
|
||||
</button>
|
||||
<EmojiPicker
|
||||
onSelect={insertEmoji}
|
||||
disabled={sessionEnded || !sessionId || sending}
|
||||
className="w-8 h-8 rounded-md border-0 bg-transparent cursor-pointer flex items-center justify-center text-neutral-400 hover:bg-neutral-50 disabled:opacity-40"
|
||||
placement="topLeft"
|
||||
/>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
@@ -551,6 +568,7 @@ const VisitorChat = ({
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
ref={textInputRef}
|
||||
className="flex-1 min-w-0 h-10 px-3 rounded-xl border border-neutral-200 bg-neutral-50 text-[13px] text-neutral-800 outline-none focus:border-[#2563eb]"
|
||||
placeholder={
|
||||
sessionEnded
|
||||
|
||||
Reference in New Issue
Block a user