Files
wecom_it_smart_desk/frontend-agent/src/stores/automation.ts
T
Simon bea288e414 feat: 2026-07-11 全量更新 - 代办集成+会议室预定+知识迭代修复+UI统一+Bug修复
== 已部署上线 (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
2026-07-11 23:13:10 +08:00

236 lines
7.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// =============================================================================
// 企微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,
}
})