Files
wecom_it_smart_desk/frontend-agent/src/stores/automation.ts
T

236 lines
7.5 KiB
TypeScript
Raw Normal View History

// =============================================================================
// 企微IT智能服务台 — 阶段5 自动化闭环 状态管理(Pinia Store,坐席端)
// =============================================================================
// 说明:管理自动化会话列表、当前会话详情,以及专用 WebSocket 实时推送。
// =============================================================================
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type {
AutomationSession,
CreateSessionPayload,
ApprovalPayload,
TakeoverPayload,
InformationItem,
PausedSession,
} from '@/api/automation'
import {
createAutomationSession,
listAutomationSessions,
getAutomationSession,
approveAutomationSession,
takeoverAutomationSession,
listPausedSessions,
agentResumeSession,
agentCloseSession,
getInfoItems,
} from '@/api/automation'
// --------------------------------------------------------------------------
// WebSocket 辅助(C8:移除 portal_token
// --------------------------------------------------------------------------
function getAgentToken(): string {
return localStorage.getItem('agent_token') || ''
}
function buildWsUrl(sessionId: string): string {
const token = getAgentToken()
const isDev = import.meta.env.DEV
const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const host = isDev ? 'localhost:8000' : window.location.host
return `${proto}//${host}/ws/automation/${sessionId}?token=${encodeURIComponent(token)}`
}
export const useAutomationStore = defineStore('automation', () => {
// ------------------------------------------------------------------------
// 状态
// ------------------------------------------------------------------------
const sessions = ref<AutomationSession[]>([])
const currentSession = ref<AutomationSession | null>(null)
const loading = ref(false)
const ws = ref<WebSocket | null>(null)
const wsSessionId = ref<string | null>(null)
const wsConnected = ref(false)
/** 暂停会话列表(复杂场景重构) */
const pausedSessions = ref<PausedSession[]>([])
/** 当前会话信息项列表(复杂场景重构) */
const infoItems = ref<InformationItem[]>([])
// ------------------------------------------------------------------------
// 计算属性
// ------------------------------------------------------------------------
const pendingSessions = computed(() =>
sessions.value.filter((s) => ['created', 'running', 'paused'].includes(s.status)),
)
// ------------------------------------------------------------------------
// 数据加载
// ------------------------------------------------------------------------
async function fetchSessions(): Promise<void> {
loading.value = true
try {
sessions.value = await listAutomationSessions()
} finally {
loading.value = false
}
}
async function fetchSession(sessionId: string): Promise<void> {
loading.value = true
try {
currentSession.value = await getAutomationSession(sessionId)
} finally {
loading.value = false
}
}
async function createSession(payload: CreateSessionPayload): Promise<AutomationSession> {
const session = await createAutomationSession(payload)
currentSession.value = session
await fetchSessions()
return session
}
async function approve(sessionId: string, decision: 'approve' | 'reject', note?: string): Promise<void> {
const payload: ApprovalPayload = { decision, note }
currentSession.value = await approveAutomationSession(sessionId, payload)
}
async function takeover(sessionId: string, agentId: string, note?: string): Promise<void> {
const payload: TakeoverPayload = { agent_id: agentId, note }
currentSession.value = await takeoverAutomationSession(sessionId, payload)
}
// ------------------------------------------------------------------------
// 复杂场景重构:暂停会话管理 / 信息项
// ------------------------------------------------------------------------
async function fetchPausedSessions(employeeId: string): Promise<void> {
pausedSessions.value = await listPausedSessions(employeeId)
}
async function agentResume(sessionId: string, note?: string): Promise<void> {
currentSession.value = await agentResumeSession(sessionId, { note })
}
async function agentClose(sessionId: string, note?: string): Promise<void> {
currentSession.value = await agentCloseSession(sessionId, { note })
}
async function fetchInfoItems(sessionId: string): Promise<void> {
infoItems.value = await getInfoItems(sessionId)
}
// ------------------------------------------------------------------------
// WebSocket
// ------------------------------------------------------------------------
function connectWs(sessionId: string): void {
disconnectWs()
const url = buildWsUrl(sessionId)
const token = getAgentToken()
const socket = new WebSocket(url, [`bearer.${token}`])
ws.value = socket
wsSessionId.value = sessionId
socket.onopen = () => {
wsConnected.value = true
}
socket.onmessage = (event: MessageEvent) => {
try {
const msg = JSON.parse(event.data)
handleWsMessage(msg)
} catch (e) {
console.error('[automation WS] 消息解析失败', e)
}
}
socket.onclose = () => {
wsConnected.value = false
}
socket.onerror = () => {
wsConnected.value = false
}
}
function disconnectWs(): void {
if (ws.value) {
ws.value.close()
ws.value = null
}
wsConnected.value = false
wsSessionId.value = null
}
function handleWsMessage(msg: { type: string; session_id?: string; data?: any }): void {
// 仅处理当前会话的事件
if (msg.session_id && wsSessionId.value && msg.session_id !== wsSessionId.value) {
return
}
switch (msg.type) {
case 'automation.progress':
case 'automation.action_required':
case 'automation.resolved':
case 'automation.takeover':
case 'automation.error':
// 有事件即刷新详情(保持简单可靠)
if (wsSessionId.value) {
fetchSession(wsSessionId.value)
}
break
// --- 复杂场景重构:新增 WS 事件 ---
case 'automation.paused':
// 会话暂停:刷新详情
if (wsSessionId.value) {
fetchSession(wsSessionId.value)
}
break
case 'automation.resumed':
// 会话恢复:刷新详情和信息项
if (wsSessionId.value) {
fetchSession(wsSessionId.value)
fetchInfoItems(wsSessionId.value)
}
break
case 'automation.info_corrected':
// 信息更正:刷新信息项
if (wsSessionId.value) {
fetchInfoItems(wsSessionId.value)
}
break
case 'automation.info_supplemented':
// 信息补充:刷新信息项
if (wsSessionId.value) {
fetchInfoItems(wsSessionId.value)
}
break
case 'automation.timeout_closed':
// 超时关闭:刷新详情
if (wsSessionId.value) {
fetchSession(wsSessionId.value)
}
break
default:
break
}
}
return {
sessions,
currentSession,
loading,
wsConnected,
pendingSessions,
pausedSessions,
infoItems,
fetchSessions,
fetchSession,
createSession,
approve,
takeover,
fetchPausedSessions,
agentResume,
agentClose,
fetchInfoItems,
connectWs,
disconnectWs,
}
})