重构: ARC-05 project.ts 上帝 store 拆分(4 子 store+barrel 兼容零改动)
拆 stores/project/{state,projects,tasks,ideas,workflow}.ts 四领域子 store(共享 state 单例 reactive 引用一致);越层 invoke approve_human_approval/cancel_workflow_node 下沉 src/api/workflow.ts;project.ts 改 barrel 组合器(实例化四子 store+re-export 所有成员,useProjectStore 单例+ProjectStore 类型保留)。所有 view(App/Dashboard/Ideas/ProjectDetail/Projects/Tasks/ToolCard)import '../stores/project' 零改动。行为零变化(含 CR-11⑪ approveHumanApproval 签名+B-34 snake_case)。批6,vue-tsc 0
This commit is contained in:
128
src/stores/project/workflow.ts
Normal file
128
src/stores/project/workflow.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
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<string, unknown>) {
|
||||
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'
|
||||
// 单选取首项(后端 decision 为单值);多选 decision 取首项作占位(后端按 decisions 走)
|
||||
const decision = selectType === 'multiple'
|
||||
? (decisions[0] ?? '')
|
||||
: (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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user