bea288e414
== 已部署上线 (9项) == - 代办事项真实数据源集成 (企微审批API 8bug修复链) - H5/坐席端 Logo样式统一+绿色背景 - 视频引导页修复 (localStorage key v2) - 坐席端 v9 Vue版本修复 (ElMessage._context) - 截图按钮 v10 修复 (getDisplayMedia user gesture) - 扫码样式恢复+H5扫码登录跳转修复 - H5截图快捷键提示 == 代码完成待部署 (3项) == - 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查) - 会议室预定-小鱼易联终端 (40文件, 40/40测试通过) - IT资产升级审批推送 (asset_service.py) == 需求文档 (2项) == - 坐席端AI辅助消息框-PRD (4项新功能确认) - 坐席端布局优化建议 v2.0 (7天计划) == 新增文档 == - 日报-2026-07-11.md - 知识迭代Bug修复报告-20260711.md - 会议室预定-部署指南.md - CHANGELOG.md 更新 == 测试 == - test_todo_integration.py: 40/40 - test_meetingroom.py: 40/40 - test_bugfix_ki_suggestions.py: 21/21
236 lines
7.5 KiB
TypeScript
236 lines
7.5 KiB
TypeScript
// =============================================================================
|
||
// 企微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,
|
||
}
|
||
})
|