重构: 拆human_node人工节点(strategy核心库)

- 新建 df-nodes/human_node_helpers.rs(32行): REJECT_KEYWORDS + is_reject_decision + contains_reject(B-260615-05拒绝语义保留)
- human_node.rs 850→831: HumanNode struct+impl+tests保留 + use helpers(impl块约束主体内联)
- lib.rs: mod human_node_helpers
主代兜底(独立 -p df-nodes): cargo 0 + test 82(B-260615-05 reject全绿)
strategy: 核心库, 纯函数+常量抽离, impl保留; human_node主体内联execute大(impl约束, 可拆有限)
git add指定(df-nodes/*)
This commit is contained in:
2026-06-19 11:47:40 +08:00
parent 356c8f27f8
commit a2330de2a8
3 changed files with 39 additions and 25 deletions

View File

@@ -1,4 +1,7 @@
//! 人工审批节点 — 阻塞工作流,等待人工确认或输入 //! 人工审批节点 — 阻塞工作流,等待人工确认或输入
//!
//! 拒绝语义化关键字判定等纯逻辑见 `human_node_helpers`(本文件只保留
//! HumanNode 的 struct + impl,impl 块约束)。
use async_trait::async_trait; use async_trait::async_trait;
use std::time::Duration; use std::time::Duration;
@@ -6,31 +9,9 @@ use tokio::sync::broadcast;
use df_workflow::node::{Node, NodeContext, NodeOutput, NodeResult, NodeSchema}; use df_workflow::node::{Node, NodeContext, NodeOutput, NodeResult, NodeSchema};
use df_types::events::{SelectType, WorkflowEvent}; use df_types::events::{SelectType, WorkflowEvent};
/// F-260616-06 阶段2: 拒绝语义化关键字。 // 抽离的纯函数/常量(glob 引入,tests `use super::*` 间接可见)
/// decision 归一化(去空白 + 小写)后命中此集合 → 审批拒绝 → 节点返 Err(触发工作流 failed)。 #[allow(unused_imports)]
/// use crate::human_node_helpers::{contains_reject, is_reject_decision, REJECT_KEYWORDS};
/// 识别范围(避免误伤):
/// - 仅当节点 options 非空且该 decision ∈ options 时拒绝 —— 前端从受控选项中选择,语义可信;
/// - options 空(自由文本)时同样按关键字判定 —— 仅当文本明确为拒绝词才拒绝,
/// 其余自由文本一律视为通过(向后兼容,不阻断自由反馈)。
///
/// 关键字集合与前端/IPC 的 options 命名约定对齐:「拒绝/驳回/退回」中文 +
/// 「reject/decline/deny/no/block」英文覆盖默认 options `["同意","拒绝"]`。
const REJECT_KEYWORDS: &[&str] = &[
"拒绝", "驳回", "退回", "否决",
"reject", "decline", "declined", "deny", "denied", "no", "block",
];
/// 判定单个 decision 是否为拒绝选项(归一化后命中 REJECT_KEYWORDS
fn is_reject_decision(d: &str) -> bool {
let normalized = d.trim().to_lowercase();
REJECT_KEYWORDS.iter().any(|k| normalized == *k)
}
/// 判定 picked 集合是否含拒绝选项:任一项命中即视为整单拒绝(多选场景「选了驳回」即驳回)。
fn contains_reject(picked: &[String]) -> bool {
picked.iter().any(|d| is_reject_decision(d))
}
/// 人工审批节点(阻塞节点) /// 人工审批节点(阻塞节点)
pub struct HumanNode; pub struct HumanNode;

View File

@@ -0,0 +1,32 @@
//! 人工审批节点辅助函数/类型 — 拒绝语义化关键字判定等纯逻辑
//!
//! 从 human_node.rs 抽离的纯函数/常量(execute 与关键字判定解耦,便于单测覆盖)。
//! HumanNode 的 struct + impl 仍保留在 human_node.rs(impl 块约束)。
//!
//! B-260615-05 / CR-260618-15: 拒绝语义化保留(executor set_failed → 推进链退回)。
/// F-260616-06 阶段2: 拒绝语义化关键字。
/// decision 归一化(去空白 + 小写)后命中此集合 → 审批拒绝 → 节点返 Err(触发工作流 failed)。
///
/// 识别范围(避免误伤):
/// - 仅当节点 options 非空且该 decision ∈ options 时拒绝 —— 前端从受控选项中选择,语义可信;
/// - options 空(自由文本)时同样按关键字判定 —— 仅当文本明确为拒绝词才拒绝,
/// 其余自由文本一律视为通过(向后兼容,不阻断自由反馈)。
///
/// 关键字集合与前端/IPC 的 options 命名约定对齐:「拒绝/驳回/退回」中文 +
/// 「reject/decline/deny/no/block」英文覆盖默认 options `["同意","拒绝"]`。
pub(super) const REJECT_KEYWORDS: &[&str] = &[
"拒绝", "驳回", "退回", "否决",
"reject", "decline", "declined", "deny", "denied", "no", "block",
];
/// 判定单个 decision 是否为拒绝选项(归一化后命中 REJECT_KEYWORDS
pub(super) fn is_reject_decision(d: &str) -> bool {
let normalized = d.trim().to_lowercase();
REJECT_KEYWORDS.iter().any(|k| normalized == *k)
}
/// 判定 picked 集合是否含拒绝选项:任一项命中即视为整单拒绝(多选场景「选了驳回」即驳回)。
pub(super) fn contains_reject(picked: &[String]) -> bool {
picked.iter().any(|d| is_reject_decision(d))
}

View File

@@ -4,6 +4,7 @@ pub mod ai_node;
#[allow(dead_code)] #[allow(dead_code)]
mod ai_node_helpers; mod ai_node_helpers;
pub mod human_node; pub mod human_node;
mod human_node_helpers;
pub mod script_node; pub mod script_node;
pub mod task_advance_node; pub mod task_advance_node;
pub mod task_state_machine; pub mod task_state_machine;