欢迎语支持多段配置与图片

租户可配置有序文本/图片欢迎语;设置页支持增删排序与上传,Widget 空会话按序展示;兼容旧 welcome_message 字段。
This commit is contained in:
yml2213
2026-07-17 21:47:21 +08:00
parent 7319799ec4
commit 54d23bb595
8 changed files with 504 additions and 51 deletions
+58 -8
View File
@@ -18,6 +18,34 @@ interface Message {
const defaultQuickQuestions = ['查询订单状态', '退换货政策', '配送时效说明']
type WelcomeSegment = { type: 'text' | 'image'; content: string }
const defaultWelcomeSegments: WelcomeSegment[] = [
{ type: 'text', content: '您好!欢迎咨询,请问有什么可以帮您?' },
]
function parseWelcomeSegments(data: {
welcome_messages?: unknown
welcome_message?: string
}): WelcomeSegment[] {
if (Array.isArray(data.welcome_messages) && data.welcome_messages.length > 0) {
const segs: WelcomeSegment[] = []
for (const raw of data.welcome_messages) {
if (!raw || typeof raw !== 'object') continue
const item = raw as { type?: string; content?: string }
const content = typeof item.content === 'string' ? item.content.trim() : ''
if (!content) continue
if (item.type === 'image') segs.push({ type: 'image', content })
else segs.push({ type: 'text', content })
}
if (segs.length > 0) return segs
}
if (typeof data.welcome_message === 'string' && data.welcome_message.trim()) {
return [{ type: 'text', content: data.welcome_message.trim() }]
}
return defaultWelcomeSegments
}
type LayoutMode = 'floating' | 'fill'
interface VisitorChatProps {
@@ -76,7 +104,7 @@ const VisitorChat = ({
const [sendError, setSendError] = useState('')
const [agentsOnline, setAgentsOnline] = useState(true)
const [offlinePrompt, setOfflinePrompt] = useState('当前无客服在线,请留言并留下联系方式,我们上线后会尽快回复您。')
const [welcomeMessage, setWelcomeMessage] = useState('您好!欢迎咨询,请问有什么可以帮您?')
const [welcomeSegments, setWelcomeSegments] = useState<WelcomeSegment[]>(defaultWelcomeSegments)
const [displayName, setDisplayName] = useState('在线客服')
const [agentName, setAgentName] = useState('')
const [leaveName, setLeaveName] = useState('')
@@ -291,7 +319,7 @@ const VisitorChat = ({
visitorTokenRef.current = token
setAgentsOnline(Boolean(data.agents_online))
if (data.offline_prompt) setOfflinePrompt(data.offline_prompt)
if (data.welcome_message) setWelcomeMessage(data.welcome_message)
setWelcomeSegments(parseWelcomeSegments(data))
if (data.display_name) setDisplayName(data.display_name)
if (data.agent_name) setAgentName(data.agent_name)
else if (data.agent_nickname) setAgentName(data.agent_nickname)
@@ -786,12 +814,34 @@ const VisitorChat = ({
<section className="flex-1 overflow-y-auto p-4 flex flex-col gap-3 bg-neutral-50 no-scrollbar">
{showWelcome && (
<div className="flex flex-col items-center gap-3">
<div className="px-4 py-2 rounded-xl bg-white border border-neutral-200 max-w-[85%] text-center">
<p className="m-0 text-[13px] text-neutral-600 leading-normal">
{agentsOnline ? welcomeMessage : offlinePrompt}
</p>
</div>
<div className="flex flex-col items-start gap-2 max-w-[90%]">
{agentsOnline ? (
welcomeSegments.map((seg, i) =>
seg.type === 'image' ? (
<div
key={`w-${i}`}
className="rounded-xl bg-white border border-neutral-200 p-1.5"
>
<ChatImage
src={seg.content}
alt="欢迎图"
className="max-w-[220px] max-h-[220px]"
/>
</div>
) : (
<div
key={`w-${i}`}
className="px-4 py-2.5 rounded-xl bg-white border border-neutral-200 text-[13px] text-neutral-700 leading-normal whitespace-pre-wrap"
>
{seg.content}
</div>
),
)
) : (
<div className="px-4 py-2.5 rounded-xl bg-white border border-neutral-200 text-[13px] text-neutral-600 leading-normal">
{offlinePrompt}
</div>
)}
</div>
)}