欢迎语支持多段配置与图片
租户可配置有序文本/图片欢迎语;设置页支持增删排序与上传,Widget 空会话按序展示;兼容旧 welcome_message 字段。
This commit is contained in:
@@ -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>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user