支持坐席切换在线状态,转接列表展示状态
侧栏可切换在线/忙碌/离线;转接弹窗显示状态点与标签,列表含在线与忙碌坐席。
This commit is contained in:
+78
-17
@@ -1,53 +1,114 @@
|
||||
import { createContext, useContext, useState, useCallback, type ReactNode } from 'react'
|
||||
import { createContext, useContext, useState, useCallback, useEffect, type ReactNode } from 'react'
|
||||
import { setToken } from '@/services/request'
|
||||
import { login as loginApi, type LoginResult } from '@/services/api'
|
||||
import {
|
||||
getMe,
|
||||
login as loginApi,
|
||||
updateMyStatus,
|
||||
type AgentPresence,
|
||||
type LoginResult,
|
||||
} from '@/services/api'
|
||||
|
||||
interface AuthState {
|
||||
user: LoginResult | null
|
||||
loading: boolean
|
||||
login: (username: string, password: string) => Promise<LoginResult>
|
||||
user: LoginResult | null
|
||||
loading: boolean
|
||||
login: (username: string, password: string) => Promise<LoginResult>
|
||||
logout: () => void
|
||||
/** 切换本人在线 / 忙碌 / 离线 */
|
||||
setPresence: (status: AgentPresence) => Promise<void>
|
||||
}
|
||||
|
||||
const AuthContext = createContext<AuthState>({
|
||||
user: null, loading: false,
|
||||
login: async () => { throw new Error('认证上下文未初始化') }, logout: () => {},
|
||||
user: null,
|
||||
loading: false,
|
||||
login: async () => { throw new Error('认证上下文未初始化') },
|
||||
logout: () => {},
|
||||
setPresence: async () => {},
|
||||
})
|
||||
|
||||
function persistUser(u: LoginResult | null) {
|
||||
if (!u) {
|
||||
localStorage.removeItem('auth_user')
|
||||
return
|
||||
}
|
||||
localStorage.setItem('auth_user', JSON.stringify(u))
|
||||
}
|
||||
|
||||
export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
const [user, setUser] = useState<LoginResult | null>(() => {
|
||||
const saved = localStorage.getItem('auth_user')
|
||||
if (saved) {
|
||||
const u = JSON.parse(saved) as LoginResult
|
||||
setToken(u.token)
|
||||
return u
|
||||
try {
|
||||
const u = JSON.parse(saved) as LoginResult
|
||||
setToken(u.token)
|
||||
return u
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// 刷新后同步服务端真实状态(含 status)
|
||||
useEffect(() => {
|
||||
if (!user?.token) return
|
||||
let cancelled = false
|
||||
getMe()
|
||||
.then(res => {
|
||||
if (cancelled || !res.data) return
|
||||
setUser(prev => {
|
||||
if (!prev) return prev
|
||||
const next = {
|
||||
...prev,
|
||||
nickname: res.data.nickname || prev.nickname,
|
||||
role: res.data.role || prev.role,
|
||||
status: res.data.status || prev.status || 'offline',
|
||||
}
|
||||
persistUser(next)
|
||||
return next
|
||||
})
|
||||
})
|
||||
.catch(() => { /* 忽略:token 失效会在后续请求里处理 */ })
|
||||
return () => { cancelled = true }
|
||||
// 仅挂载时拉一次
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [user?.token])
|
||||
|
||||
const login = useCallback(async (username: string, password: string) => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await loginApi({ username, password })
|
||||
const u = res.data
|
||||
setToken(u.token)
|
||||
setUser(u)
|
||||
localStorage.setItem('auth_user', JSON.stringify(u))
|
||||
return u
|
||||
const u: LoginResult = { ...res.data, status: res.data.status || 'online' }
|
||||
setToken(u.token)
|
||||
setUser(u)
|
||||
persistUser(u)
|
||||
return u
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const setPresence = useCallback(async (status: AgentPresence) => {
|
||||
const res = await updateMyStatus(status)
|
||||
const nextStatus = (res.data?.status || status) as string
|
||||
setUser(prev => {
|
||||
if (!prev) return prev
|
||||
const next = { ...prev, status: nextStatus }
|
||||
persistUser(next)
|
||||
return next
|
||||
})
|
||||
}, [])
|
||||
|
||||
const logout = useCallback(() => {
|
||||
// 尽力把状态置为离线,不阻塞退出
|
||||
void updateMyStatus('offline').catch(() => {})
|
||||
setToken('')
|
||||
setUser(null)
|
||||
localStorage.removeItem('auth_user')
|
||||
persistUser(null)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ user, loading, login, logout }}>
|
||||
<AuthContext.Provider value={{ user, loading, login, logout, setPresence }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user