支持坐席切换在线状态,转接列表展示状态
侧栏可切换在线/忙碌/离线;转接弹窗显示状态点与标签,列表含在线与忙碌坐席。
This commit is contained in:
@@ -148,6 +148,20 @@ function listStatusMeta(session: Session) {
|
||||
return { label: '进行中', bar: '#2563eb', avatarBg: '#eff6ff', avatarColor: '#2563eb', dot: '#2563eb' }
|
||||
}
|
||||
|
||||
/** 坐席在线状态(转接列表) */
|
||||
function agentStatusMeta(status: string) {
|
||||
switch (status) {
|
||||
case 'online':
|
||||
return { text: '在线', dot: '#16a34a', bg: '#ecfdf5', color: '#15803d' }
|
||||
case 'busy':
|
||||
return { text: '忙碌', dot: '#d97706', bg: '#fffbeb', color: '#b45309' }
|
||||
case 'disabled':
|
||||
return { text: '停用', dot: '#94a3b8', bg: '#f1f5f9', color: '#64748b' }
|
||||
default:
|
||||
return { text: '离线', dot: '#94a3b8', bg: '#f1f5f9', color: '#64748b' }
|
||||
}
|
||||
}
|
||||
|
||||
function relativeTime(iso?: string | null) {
|
||||
if (!iso) return ''
|
||||
const diff = Date.now() - new Date(iso).getTime()
|
||||
@@ -964,17 +978,23 @@ const Dashboard = () => {
|
||||
const openTransfer = async () => {
|
||||
if (!selected) return
|
||||
try {
|
||||
// 默认返回在线/忙碌坐席(含 status)
|
||||
const response = await getAvailableAgents()
|
||||
setAvailableAgents((response.data || []).filter(agent => agent.id !== user?.user_id))
|
||||
setTargetAgentID(undefined)
|
||||
setTransferOpen(true)
|
||||
} catch {
|
||||
antMsg.error('加载在线客服失败')
|
||||
antMsg.error('加载可转接坐席失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleTransfer = async () => {
|
||||
if (!selected || !targetAgentID) return
|
||||
const target = availableAgents.find(a => a.id === targetAgentID)
|
||||
if (target && target.status !== 'online' && target.status !== 'busy') {
|
||||
antMsg.warning('只能转接给在线或忙碌的坐席')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await transferSession(selected.id, targetAgentID)
|
||||
antMsg.success('会话已转接')
|
||||
@@ -1883,15 +1903,63 @@ const Dashboard = () => {
|
||||
)}
|
||||
</aside>
|
||||
|
||||
<Modal title="转接会话" open={transferOpen} onCancel={() => setTransferOpen(false)} onOk={handleTransfer} okButtonProps={{ disabled: !targetAgentID }}>
|
||||
<p className="text-sm text-neutral-500 mb-3">请选择一位在线客服接手当前会话。</p>
|
||||
<Select
|
||||
className="w-full"
|
||||
placeholder="选择客服"
|
||||
value={targetAgentID}
|
||||
onChange={setTargetAgentID}
|
||||
options={availableAgents.map(agent => ({ value: agent.id, label: agent.nickname }))}
|
||||
/>
|
||||
<Modal
|
||||
title="转接会话"
|
||||
open={transferOpen}
|
||||
onCancel={() => setTransferOpen(false)}
|
||||
onOk={handleTransfer}
|
||||
okButtonProps={{
|
||||
disabled: !targetAgentID || (() => {
|
||||
const t = availableAgents.find(a => a.id === targetAgentID)
|
||||
return Boolean(t && t.status !== 'online' && t.status !== 'busy')
|
||||
})(),
|
||||
}}
|
||||
>
|
||||
<p className="text-sm text-neutral-500 mb-3">请选择接手坐席(绿色在线 / 橙色忙碌)。</p>
|
||||
{availableAgents.length === 0 ? (
|
||||
<div className="text-sm text-neutral-400 py-6 text-center border border-dashed border-neutral-200 rounded-lg">
|
||||
当前没有其他可转接坐席
|
||||
</div>
|
||||
) : (
|
||||
<Select
|
||||
className="w-full"
|
||||
placeholder="选择坐席"
|
||||
value={targetAgentID}
|
||||
onChange={setTargetAgentID}
|
||||
optionLabelProp="label"
|
||||
options={availableAgents.map(agent => {
|
||||
const st = agentStatusMeta(agent.status)
|
||||
return {
|
||||
value: agent.id,
|
||||
// 选中后输入框展示:昵称 + 状态
|
||||
label: `${agent.nickname}(${st.text})`,
|
||||
disabled: agent.status !== 'online' && agent.status !== 'busy',
|
||||
}
|
||||
})}
|
||||
optionRender={option => {
|
||||
const agent = availableAgents.find(a => a.id === option.value)
|
||||
const st = agentStatusMeta(agent?.status || 'offline')
|
||||
return (
|
||||
<div className="flex items-center gap-2 py-0.5 min-w-0">
|
||||
<span
|
||||
className="inline-block w-2 h-2 rounded-full shrink-0"
|
||||
style={{ background: st.dot }}
|
||||
title={st.text}
|
||||
/>
|
||||
<span className="truncate text-neutral-800 flex-1 min-w-0">
|
||||
{agent?.nickname || option.label}
|
||||
</span>
|
||||
<span
|
||||
className="shrink-0 text-[11px] px-1.5 py-0 rounded font-medium"
|
||||
style={{ background: st.bg, color: st.color }}
|
||||
>
|
||||
{st.text}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
<Modal title="结束会话" open={endingOpen} onCancel={() => setEndingOpen(false)} onOk={handleEnd} okText="确认结束">
|
||||
<p className="text-sm text-neutral-500 mb-3">请选择本次会话的结束原因。</p>
|
||||
|
||||
Reference in New Issue
Block a user