Phase 6 功能补全: - P1-3: 消息 SSE 实时推送端点 + 前端 EventSource 连接 - P1-6: ServiceTask HTTP 调用能力 (reqwest GET/POST) - P1-7: user.deleted 事件处理 — 终止相关流程实例 - P1-8: 任务认领 (claim) 端点 + handler - P1-9: 超时检查器发布 task.timeout 事件 - P1-15: 组织/部门名称唯一性校验 (create + update) - P1-18: 消息群发 fan-out (role/department/all 批量投递) Phase 7 P3-P4 收尾: - PluginAdmin purge 按钮状态修复 - ChangePassword 最小 8 字符 + 新旧密码不同验证 - AuditLogViewer 用户名缓存 + 扩展资源类型 - InstanceMonitor 通过 definition 缓存解析 node_name - NotificationPreferences DND 时间范围校验
234 lines
6.8 KiB
Rust
234 lines
6.8 KiB
Rust
use chrono::{DateTime, Utc};
|
||
use serde::{Deserialize, Serialize};
|
||
use utoipa::ToSchema;
|
||
use uuid::Uuid;
|
||
use validator::Validate;
|
||
|
||
// --- 流程图节点/边定义 ---
|
||
|
||
/// BPMN 节点类型
|
||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, PartialEq)]
|
||
pub enum NodeType {
|
||
StartEvent,
|
||
EndEvent,
|
||
UserTask,
|
||
ServiceTask,
|
||
ExclusiveGateway,
|
||
ParallelGateway,
|
||
}
|
||
|
||
/// 流程图节点定义
|
||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||
pub struct NodeDef {
|
||
pub id: String,
|
||
#[serde(rename = "type")]
|
||
pub node_type: NodeType,
|
||
pub name: String,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub assignee_id: Option<Uuid>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub candidate_groups: Option<Vec<String>>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub service_type: Option<String>,
|
||
/// 服务任务 HTTP 调用配置
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub service_config: Option<ServiceTaskConfig>,
|
||
/// 前端渲染位置
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub position: Option<NodePosition>,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||
pub struct NodePosition {
|
||
pub x: f64,
|
||
pub y: f64,
|
||
}
|
||
|
||
/// ServiceTask HTTP 调用配置
|
||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||
pub struct ServiceTaskConfig {
|
||
/// 请求 URL
|
||
pub url: String,
|
||
/// HTTP 方法(GET / POST),默认 GET
|
||
#[serde(default = "default_method")]
|
||
pub method: String,
|
||
/// POST body 模板(支持从流程变量替换 ${var_name})
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub body: Option<serde_json::Value>,
|
||
}
|
||
|
||
fn default_method() -> String {
|
||
"GET".to_string()
|
||
}
|
||
|
||
/// 流程图连线定义
|
||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||
pub struct EdgeDef {
|
||
pub id: String,
|
||
pub source: String,
|
||
pub target: String,
|
||
/// 条件表达式(排他网关分支)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub condition: Option<String>,
|
||
/// 前端渲染标签
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub label: Option<String>,
|
||
}
|
||
|
||
/// 完整流程图
|
||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||
pub struct FlowDiagram {
|
||
pub nodes: Vec<NodeDef>,
|
||
pub edges: Vec<EdgeDef>,
|
||
}
|
||
|
||
// --- 流程定义 DTOs ---
|
||
|
||
#[derive(Debug, Serialize, ToSchema)]
|
||
pub struct ProcessDefinitionResp {
|
||
pub id: Uuid,
|
||
pub name: String,
|
||
pub key: String,
|
||
pub version: i32,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub category: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub description: Option<String>,
|
||
pub nodes: serde_json::Value,
|
||
pub edges: serde_json::Value,
|
||
pub status: String,
|
||
pub created_at: DateTime<Utc>,
|
||
pub updated_at: DateTime<Utc>,
|
||
pub lock_version: i32,
|
||
}
|
||
|
||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||
pub struct CreateProcessDefinitionReq {
|
||
#[validate(length(min = 1, max = 200, message = "流程名称不能为空"))]
|
||
pub name: String,
|
||
#[validate(length(min = 1, max = 100, message = "流程编码不能为空"))]
|
||
pub key: String,
|
||
pub category: Option<String>,
|
||
pub description: Option<String>,
|
||
pub nodes: Vec<NodeDef>,
|
||
pub edges: Vec<EdgeDef>,
|
||
}
|
||
|
||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||
pub struct UpdateProcessDefinitionReq {
|
||
#[validate(length(max = 200, message = "流程名称过长"))]
|
||
pub name: Option<String>,
|
||
pub category: Option<String>,
|
||
pub description: Option<String>,
|
||
pub nodes: Option<Vec<NodeDef>>,
|
||
pub edges: Option<Vec<EdgeDef>>,
|
||
pub version: i32,
|
||
}
|
||
|
||
// --- 流程实例 DTOs ---
|
||
|
||
#[derive(Debug, Serialize, ToSchema)]
|
||
pub struct ProcessInstanceResp {
|
||
pub id: Uuid,
|
||
pub definition_id: Uuid,
|
||
pub definition_name: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub business_key: Option<String>,
|
||
pub status: String,
|
||
pub started_by: Uuid,
|
||
pub started_at: DateTime<Utc>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub completed_at: Option<DateTime<Utc>>,
|
||
pub created_at: DateTime<Utc>,
|
||
/// 当前活跃的 token 位置
|
||
pub active_tokens: Vec<TokenResp>,
|
||
pub version: i32,
|
||
}
|
||
|
||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||
pub struct StartInstanceReq {
|
||
pub definition_id: Uuid,
|
||
pub business_key: Option<String>,
|
||
/// 初始流程变量
|
||
pub variables: Option<Vec<SetVariableReq>>,
|
||
}
|
||
|
||
// --- Token DTOs ---
|
||
|
||
#[derive(Debug, Serialize, ToSchema)]
|
||
pub struct TokenResp {
|
||
pub id: Uuid,
|
||
pub node_id: String,
|
||
pub status: String,
|
||
pub created_at: DateTime<Utc>,
|
||
}
|
||
|
||
// --- 任务 DTOs ---
|
||
|
||
#[derive(Debug, Serialize, ToSchema)]
|
||
pub struct TaskResp {
|
||
pub id: Uuid,
|
||
pub instance_id: Uuid,
|
||
pub token_id: Uuid,
|
||
pub node_id: String,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub node_name: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub assignee_id: Option<Uuid>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub candidate_groups: Option<serde_json::Value>,
|
||
pub status: String,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub outcome: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub form_data: Option<serde_json::Value>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub due_date: Option<DateTime<Utc>>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub completed_at: Option<DateTime<Utc>>,
|
||
pub created_at: DateTime<Utc>,
|
||
/// 流程定义名称(用于列表展示)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub definition_name: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub business_key: Option<String>,
|
||
pub version: i32,
|
||
}
|
||
|
||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||
pub struct CompleteTaskReq {
|
||
#[validate(length(min = 1, max = 50, message = "审批结果不能为空"))]
|
||
pub outcome: String,
|
||
pub form_data: Option<serde_json::Value>,
|
||
}
|
||
|
||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||
pub struct DelegateTaskReq {
|
||
pub delegate_to: Uuid,
|
||
}
|
||
|
||
// --- 流程变量 DTOs ---
|
||
|
||
#[derive(Debug, Serialize, ToSchema)]
|
||
pub struct ProcessVariableResp {
|
||
pub id: Uuid,
|
||
pub name: String,
|
||
pub var_type: String,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub value_string: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub value_number: Option<f64>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub value_boolean: Option<bool>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub value_date: Option<DateTime<Utc>>,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Deserialize, Validate, ToSchema)]
|
||
pub struct SetVariableReq {
|
||
#[validate(length(min = 1, max = 100, message = "变量名不能为空"))]
|
||
pub name: String,
|
||
pub var_type: Option<String>,
|
||
pub value: serde_json::Value,
|
||
}
|