import { workflowApi } from '../../api' import { state, _eventUnlisten, setEventUnlisten } from './state' /** * 工作流 + 审批子 store(共享全局 state)。 * * 越层 invoke(approve_human_approval / cancel_workflow_node) 已下沉到 * src/api/workflow.ts,本子 store 不再直接 invoke IPC。 */ export function createWorkflowStore() { async function runWorkflow(name: string, dag: unknown, config?: Record) { return await workflowApi.run(name, dag, config) } async function loadWorkflowExecutions() { try { state.workflowExecutions = await workflowApi.listExecutions() } catch (e: any) { state.error = e?.toString() ?? '加载工作流记录失败' } } async function startEventListener() { if (_eventUnlisten) return _eventUnlisten const unlisten = await workflowApi.onEvent((payload) => { try { // 固时间戳(FR-C1):formattedEvents computed 重算时用事件发生时刻,非当前时刻 state.liveEvents.push({ ...payload, _ts: Date.now() }) // 限长(FR-R3):防 liveEvents 无限增长撑爆内存,保留最近 200 条 if (state.liveEvents.length > 200) { state.liveEvents.splice(0, state.liveEvents.length - 200) } // 处理人工审批请求 // WorkflowEvent serde tag=type rename_all=snake_case → type='human_approval_request',字段扁平(无 data 包装)(B-03b-R7) if (payload.event?.type === 'human_approval_request') { state.pendingApproval = payload.event as unknown as typeof state.pendingApproval } } catch (e) { console.error('处理工作流事件失败:', e, payload) } }) setEventUnlisten(unlisten) return unlisten } function clearLiveEvents() { state.liveEvents = [] } /** * 发送审批响应。 * * 统一以 decisions 数组表达选择,按 pendingApproval.select_type 判定单/多选: * - 单选(select_type='single' 或缺省):取 decisions[0] 作为后端 decision 单值; * - 多选(select_type='multiple'):decisions 透传全量。 * * CR-11⑪:签名保持 approveHumanApproval(decisions: string[], comment?)。 * F-260615-01: decisions/select_type 透传,与后端 IPC 签名对齐。 */ async function approveHumanApproval( decisions: string[], comment?: string, ) { if (!state.pendingApproval) return const selectType = state.pendingApproval.select_type ?? 'single' // CR-260615-18:删死逻辑三元(原 selectType 多/单分支返回值相同) // 单选取首项(后端 decision 单值);多选 decision 取首项占位(后端按 decisions 走) const decision = decisions[0] ?? '' try { // R-PD-5: 透传 options 闭环后端校验(options 非空时 decision 必须 ∈ options,否则 IPC 报错)。 // options 来自已收到的 HumanApprovalRequest 事件 payload(IPC 无法访问节点 config)。 // B-260615-34:snake_case 由 api 层对齐后端 workflow.rs:211 await workflowApi.approveHumanApproval({ execution_id: state.pendingApproval.execution_id, node_id: state.pendingApproval.node_id, decision, comment, options: state.pendingApproval.options ?? [], decisions, select_type: selectType, }) // 清除待审批状态 state.pendingApproval = null } catch (error) { console.error('审批失败:', error) } } /** 取消当前待审批节点(调 cancel_workflow_node IPC 置节点 Cancelled) */ async function cancelHumanApproval() { if (!state.pendingApproval) return try { await workflowApi.cancelHumanApproval({ execution_id: state.pendingApproval.execution_id, node_id: state.pendingApproval.node_id, }) // 清除待审批状态 state.pendingApproval = null } catch (error) { console.error('取消审批失败:', error) } } function stopEventListener() { if (_eventUnlisten) { try { _eventUnlisten() } catch (e) { console.error('停止事件监听失败:', e) } setEventUnlisten(null) } } return { runWorkflow, loadWorkflowExecutions, startEventListener, stopEventListener, clearLiveEvents, approveHumanApproval, cancelHumanApproval, } }