实现 P0 自动分配、离线留言与可嵌入 Widget SDK

- 会话创建时按负载自动分配在线客服,无客服则进入离线模式
- 新增 /api/widget/leave-message 沉淀联系方式与留言事件
- 访客端离线留言表单;工作台展示离线留言/自动分配事件
- 提供 public/widget.js + /widget/embed 嵌入方案
This commit is contained in:
yml2213
2026-07-15 11:09:50 +08:00
parent d105840b1f
commit 9485c28abd
11 changed files with 930 additions and 282 deletions
+20 -7
View File
@@ -253,7 +253,7 @@ const Dashboard = () => {
return tb - ta
})
const notes = detail?.events.filter(event => event.action === 'note').slice().reverse() || []
const notes = detail?.events.filter(event => event.action === 'note' || event.action === 'offline_leave' || event.action === 'auto_assign').slice().reverse() || []
const emitTyping = () => {
if (!selectedId || !canOperate) return
@@ -899,12 +899,25 @@ const Dashboard = () => {
<div className="space-y-2 max-h-40 overflow-auto">
{notes.length === 0 ? (
<div className="text-xs text-neutral-400"></div>
) : notes.map(note => (
<div key={note.id} className="bg-amber-50 text-amber-900 rounded-lg p-2 text-xs whitespace-pre-wrap border border-amber-100">
{note.detail}
<div className="text-amber-600/70 mt-1">{new Date(note.created_at).toLocaleString('zh-CN')}</div>
</div>
))}
) : notes.map(note => {
const isLeave = note.action === 'offline_leave'
const isAssign = note.action === 'auto_assign'
const box = isLeave
? 'bg-orange-50 text-orange-900 border-orange-100'
: isAssign
? 'bg-blue-50 text-blue-900 border-blue-100'
: 'bg-amber-50 text-amber-900 border-amber-100'
const timeCls = isLeave ? 'text-orange-600/70' : isAssign ? 'text-blue-600/70' : 'text-amber-600/70'
return (
<div key={note.id} className={`rounded-lg p-2 text-xs whitespace-pre-wrap border ${box}`}>
{(isLeave || isAssign) && (
<div className="font-medium mb-0.5">{isLeave ? '离线留言' : '自动分配'}</div>
)}
{note.detail}
<div className={`mt-1 ${timeCls}`}>{new Date(note.created_at).toLocaleString('zh-CN')}</div>
</div>
)
})}
</div>
{canOperate && (
<div className="mt-2 flex gap-1">