优化: B-03b-R10前端审批(终态清pending+互斥锁防重复IPC)
This commit is contained in:
@@ -5,6 +5,11 @@ import { state, _eventUnlisten, setEventUnlisten } from './state'
|
||||
// composable 外全局 i18n 实例(非 setup 上下文)
|
||||
const t = ((i18n as any).global.t as (k: string) => string).bind((i18n as any).global)
|
||||
|
||||
// B-03b-R10(⑦ 互斥): 审批响应/取消 IPC 进行中标记(模块级单例,createWorkflowStore 每会话只跑一次)。
|
||||
// 防双击/连点在同一轮 IPC 未返回前发起第二次(后端无幂等键,第二次会重复消费 Request 触发
|
||||
// "node already completed" 类报错)。store 层守卫优于按钮 disabled: 共享单例 state,跨调用方统一。
|
||||
let _approvalInFlight = false
|
||||
|
||||
/**
|
||||
* 工作流 + 审批子 store(共享全局 state)。
|
||||
*
|
||||
@@ -49,6 +54,20 @@ export function createWorkflowStore() {
|
||||
if (payload.event?.type === 'human_approval_request') {
|
||||
state.pendingApproval = payload.event as unknown as typeof state.pendingApproval
|
||||
}
|
||||
// B-03b-R10(⑤ 终态不清): 工作流走到终态(completed/failed)或审批节点被取消时,
|
||||
// 若 pendingApproval 仍属于本次 execution,说明该审批未经 approve/cancel 正常路径关闭
|
||||
// (上游节点失败/工作流被整体取消/用户「稍后」关闭弹窗但 state 仍残留),清掉陈旧态
|
||||
// 避免下次进 ProjectDetail 时 watch immediate 误判仍有待审批。
|
||||
// 按 execution_id 限定: 并发工作流场景不清掉他人家的 pending(④ 单槽根因另议,见审查报告)。
|
||||
else if (
|
||||
state.pendingApproval &&
|
||||
state.pendingApproval.execution_id === payload.execution_id &&
|
||||
(payload.event?.type === 'workflow_completed' ||
|
||||
payload.event?.type === 'workflow_failed' ||
|
||||
payload.event?.type === 'node_cancelled')
|
||||
) {
|
||||
state.pendingApproval = null
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('处理工作流事件失败:', e, payload)
|
||||
}
|
||||
@@ -76,6 +95,9 @@ export function createWorkflowStore() {
|
||||
comment?: string,
|
||||
) {
|
||||
if (!state.pendingApproval) return
|
||||
// B-03b-R10(⑦ 互斥): 上一轮 IPC 未返回,忽略重复点击(连点/双击)
|
||||
if (_approvalInFlight) return
|
||||
_approvalInFlight = true
|
||||
const selectType = state.pendingApproval.select_type ?? 'single'
|
||||
// CR-260615-18:删死逻辑三元(原 selectType 多/单分支返回值相同)
|
||||
// 单选取首项(后端 decision 单值);多选 decision 取首项占位(后端按 decisions 走)
|
||||
@@ -100,12 +122,18 @@ export function createWorkflowStore() {
|
||||
} catch (error) {
|
||||
console.error('审批失败:', error)
|
||||
state.error = error?.toString() ?? t('projects.err.approveFailed')
|
||||
} finally {
|
||||
// B-03b-R10(⑦ 互斥): 无论成功/失败,IPC 已返回,释放重入锁
|
||||
_approvalInFlight = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 取消当前待审批节点(调 cancel_workflow_node IPC 置节点 Cancelled) */
|
||||
async function cancelHumanApproval() {
|
||||
if (!state.pendingApproval) return
|
||||
// B-03b-R10(⑦ 互斥): 上一轮 IPC 未返回,忽略重复点击
|
||||
if (_approvalInFlight) return
|
||||
_approvalInFlight = true
|
||||
|
||||
try {
|
||||
await workflowApi.cancelHumanApproval({
|
||||
@@ -117,6 +145,9 @@ export function createWorkflowStore() {
|
||||
} catch (error) {
|
||||
console.error('取消审批失败:', error)
|
||||
state.error = error?.toString() ?? t('projects.err.cancelFailed')
|
||||
} finally {
|
||||
// B-03b-R10(⑦ 互斥): 无论成功/失败,IPC 已返回,释放重入锁
|
||||
_approvalInFlight = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user