新增: 初始化 DevFlow 项目仓库

Tauri 2 + Vue 3 + Vite 6 桌面应用,Rust workspace 含 13 个 crate
(df-ai / df-storage / df-workflow / df-core / df-execute 等)。
核心能力:AI 聊天 agentic 循环(工具调用+人工审批)、工作流引擎、
任务/想法/项目/阶段管理、可追溯性,及配套前端组件。
This commit is contained in:
2026-06-12 01:31:05 +08:00
commit 98393b4908
178 changed files with 27859 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
//! 人工审批节点 — 阻塞工作流,等待人工确认或输入
use async_trait::async_trait;
use std::time::Duration;
use tokio::time;
use df_workflow::node::{Node, NodeContext, NodeOutput, NodeResult, NodeSchema};
use df_core::events::WorkflowEvent;
/// 人工审批节点(阻塞节点)
pub struct HumanNode;
#[async_trait]
impl Node for HumanNode {
async fn execute(&self, ctx: NodeContext) -> NodeResult {
let config = ctx.config.as_object().cloned().unwrap_or_default();
let title = config.get("title")
.and_then(|v| v.as_str())
.unwrap_or("请确认");
let description = config.get("description")
.and_then(|v| v.as_str())
.unwrap_or("");
let options = config.get("options")
.and_then(|v| v.as_array())
.map(|arr| arr.iter()
.filter_map(|v| v.as_str())
.collect::<Vec<_>>())
.unwrap_or_else(|| vec!["同意", "拒绝"]);
// 发送人工审批请求到事件总线
let _ = ctx.event_bus.send(WorkflowEvent::HumanApprovalRequest {
execution_id: ctx.execution_id.clone(),
node_id: ctx.node_id.clone(),
title: title.to_string(),
description: description.to_string(),
options: options.iter().map(|s| s.to_string()).collect(),
});
// 等待用户响应(最多等待 1 小时)
let timeout = Duration::from_secs(3600);
let start_time = std::time::Instant::now();
loop {
// 检查是否超时
if start_time.elapsed() > timeout {
return Err(anyhow::anyhow!("人工审批超时"));
}
// 检查节点是否被取消
if ctx.node_status.is_cancelled(&ctx.node_id) {
return Err(anyhow::anyhow!("人工审批被取消"));
}
// TODO: 检查审批响应(需要前端实现)
// 目前直接返回同意
let output = serde_json::json!({
"decision": "同意",
"comment": "",
});
return Ok(NodeOutput::from_value(output));
}
}
fn schema(&self) -> NodeSchema {
NodeSchema {
params: serde_json::json!({
"type": "object",
"properties": {
"title": { "type": "string" },
"description": { "type": "string" },
"options": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["title"]
}),
output: serde_json::json!({
"type": "object",
"properties": {
"decision": { "type": "string" },
"comment": { "type": "string" }
}
}),
}
}
fn is_blocking(&self) -> bool {
true
}
fn node_type(&self) -> &str {
"human"
}
}