173 lines
5.3 KiB
TypeScript
173 lines
5.3 KiB
TypeScript
|
|
// =============================================================================
|
||
|
|
// 企微IT智能服务台 — 阶段5 自动化闭环 状态管理(Pinia Store,坐席端)
|
||
|
|
// =============================================================================
|
||
|
|
// 说明:管理自动化会话列表、当前会话详情,以及专用 WebSocket 实时推送。
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
import { defineStore } from 'pinia'
|
||
|
|
import { ref, computed } from 'vue'
|
||
|
|
import type {
|
||
|
|
AutomationSession,
|
||
|
|
CreateSessionPayload,
|
||
|
|
ApprovalPayload,
|
||
|
|
TakeoverPayload,
|
||
|
|
} from '@/api/automation'
|
||
|
|
import {
|
||
|
|
createAutomationSession,
|
||
|
|
listAutomationSessions,
|
||
|
|
getAutomationSession,
|
||
|
|
approveAutomationSession,
|
||
|
|
takeoverAutomationSession,
|
||
|
|
} from '@/api/automation'
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------------
|
||
|
|
// WebSocket 辅助
|
||
|
|
// --------------------------------------------------------------------------
|
||
|
|
function getAgentToken(): string {
|
||
|
|
return (
|
||
|
|
localStorage.getItem('agent_token') ||
|
||
|
|
localStorage.getItem('portal_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 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)
|
||
|
|
}
|
||
|
|
|
||
|
|
// ------------------------------------------------------------------------
|
||
|
|
// 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
|
||
|
|
default:
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
sessions,
|
||
|
|
currentSession,
|
||
|
|
loading,
|
||
|
|
wsConnected,
|
||
|
|
pendingSessions,
|
||
|
|
fetchSessions,
|
||
|
|
fetchSession,
|
||
|
|
createSession,
|
||
|
|
approve,
|
||
|
|
takeover,
|
||
|
|
connectWs,
|
||
|
|
disconnectWs,
|
||
|
|
}
|
||
|
|
})
|