feat(flows): 新增流程编辑器基础功能与相关组件
feat(backend): 添加流程模型与服务支持 feat(frontend): 实现流程编辑器UI与交互 feat(assets): 添加流程节点图标资源 feat(plugins): 实现上下文菜单和运行时插件 feat(components): 新增基础节点和侧边栏组件 feat(routes): 添加流程相关路由配置 feat(models): 创建流程和运行日志数据模型 feat(services): 实现流程服务层逻辑 feat(migration): 添加流程相关数据库迁移 feat(config): 更新前端配置支持流程编辑器 feat(utils): 增强axios错误处理和工具函数
This commit is contained in:
13
backend/src/routes/flow_run_logs.rs
Normal file
13
backend/src/routes/flow_run_logs.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use axum::{Router, routing::get, extract::{State, Query}, Json};
|
||||
use crate::{db::Db, response::ApiResponse, services::flow_run_log_service};
|
||||
|
||||
pub fn router() -> Router<Db> {
|
||||
Router::new().route("/flow_run_logs", get(list))
|
||||
}
|
||||
|
||||
async fn list(State(db): State<Db>, Query(p): Query<flow_run_log_service::ListParams>) -> Json<ApiResponse<flow_run_log_service::PageResp<flow_run_log_service::RunLogItem>>> {
|
||||
match flow_run_log_service::list(&db, p).await {
|
||||
Ok(res) => Json(ApiResponse::ok(res)),
|
||||
Err(e) => Json(ApiResponse::err(500, format!("{}", e))),
|
||||
}
|
||||
}
|
||||
71
backend/src/routes/flows.rs
Normal file
71
backend/src/routes/flows.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use axum::{Router, routing::{post, get}, extract::{State, Path, Query}, Json};
|
||||
use crate::{db::Db, response::ApiResponse, services::flow_service, error::AppError};
|
||||
use serde::Deserialize;
|
||||
use tracing::{info, error};
|
||||
use crate::middlewares::jwt::AuthUser;
|
||||
|
||||
pub fn router() -> Router<Db> {
|
||||
Router::new()
|
||||
.route("/flows", post(create).get(list))
|
||||
.route("/flows/{id}", get(get_one).put(update).delete(remove))
|
||||
.route("/flows/{id}/run", post(run))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct PageParams { page: Option<u64>, page_size: Option<u64>, keyword: Option<String> }
|
||||
|
||||
async fn list(State(db): State<Db>, Query(p): Query<PageParams>) -> Result<Json<ApiResponse<flow_service::PageResp<flow_service::FlowSummary>>>, AppError> {
|
||||
let page = p.page.unwrap_or(1);
|
||||
let page_size = p.page_size.unwrap_or(10);
|
||||
let res = flow_service::list(&db, page, page_size, p.keyword).await.map_err(flow_service::ae)?;
|
||||
Ok(Json(ApiResponse::ok(res)))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CreateReq { yaml: Option<String>, name: Option<String>, design_json: Option<serde_json::Value>, code: Option<String>, remark: Option<String> }
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct UpdateReq { yaml: Option<String>, design_json: Option<serde_json::Value>, name: Option<String>, code: Option<String>, remark: Option<String> }
|
||||
|
||||
async fn create(State(db): State<Db>, Json(req): Json<CreateReq>) -> Result<Json<ApiResponse<flow_service::FlowDoc>>, AppError> {
|
||||
info!(target = "udmin", "routes.flows.create: start");
|
||||
let res = match flow_service::create(&db, flow_service::FlowCreateReq { yaml: req.yaml, name: req.name, design_json: req.design_json, code: req.code, remark: req.remark }).await {
|
||||
Ok(r) => { info!(target = "udmin", id = %r.id, "routes.flows.create: ok"); r }
|
||||
Err(e) => {
|
||||
error!(target = "udmin", error = ?e, "routes.flows.create: failed");
|
||||
// 将错误恢复为统一映射,避免对外暴露内部细节
|
||||
return Err(flow_service::ae(e));
|
||||
}
|
||||
};
|
||||
Ok(Json(ApiResponse::ok(res)))
|
||||
}
|
||||
|
||||
async fn update(State(db): State<Db>, Path(id): Path<String>, Json(req): Json<UpdateReq>) -> Result<Json<ApiResponse<flow_service::FlowDoc>>, AppError> {
|
||||
let res = flow_service::update(&db, &id, flow_service::FlowUpdateReq { yaml: req.yaml, design_json: req.design_json, name: req.name, code: req.code, remark: req.remark }).await.map_err(flow_service::ae)?;
|
||||
Ok(Json(ApiResponse::ok(res)))
|
||||
}
|
||||
|
||||
async fn get_one(State(db): State<Db>, Path(id): Path<String>) -> Result<Json<ApiResponse<flow_service::FlowDoc>>, AppError> {
|
||||
let res = flow_service::get(&db, &id).await.map_err(flow_service::ae)?;
|
||||
Ok(Json(ApiResponse::ok(res)))
|
||||
}
|
||||
|
||||
async fn remove(State(db): State<Db>, Path(id): Path<String>) -> Result<Json<ApiResponse<serde_json::Value>>, AppError> {
|
||||
flow_service::delete(&db, &id).await.map_err(flow_service::ae)?;
|
||||
Ok(Json(ApiResponse::ok(serde_json::json!({"deleted": true}))))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RunReq { #[serde(default)] input: serde_json::Value }
|
||||
|
||||
async fn run(State(db): State<Db>, user: AuthUser, Path(id): Path<String>, Json(req): Json<RunReq>) -> Result<Json<ApiResponse<flow_service::RunResult>>, AppError> {
|
||||
match flow_service::run(&db, &id, flow_service::RunReq { input: req.input }, Some((user.uid, user.username))).await {
|
||||
Ok(r) => Ok(Json(ApiResponse::ok(r))),
|
||||
Err(e) => {
|
||||
// 同步执行:直接把后端错误详细信息返回给前端
|
||||
let mut full = e.to_string();
|
||||
for cause in e.chain().skip(1) { full.push_str(" | "); full.push_str(&cause.to_string()); }
|
||||
Err(AppError::InternalMsg(full))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,8 @@ pub mod departments;
|
||||
pub mod logs;
|
||||
// 新增岗位
|
||||
pub mod positions;
|
||||
pub mod flows;
|
||||
pub mod flow_run_logs;
|
||||
|
||||
use axum::Router;
|
||||
use crate::db::Db;
|
||||
@ -18,6 +20,7 @@ pub fn api_router() -> Router<Db> {
|
||||
.merge(menus::router())
|
||||
.merge(departments::router())
|
||||
.merge(logs::router())
|
||||
// 合并岗位路由
|
||||
.merge(flows::router())
|
||||
.merge(positions::router())
|
||||
.merge(flow_run_logs::router())
|
||||
}
|
||||
Reference in New Issue
Block a user