chore: 干净 ERP 基座 — 删除 health/ai/wechat 业务代码
删除内容: - 前端: health/(67文件), ai/(2文件), Copilot, MediaPicker, 相关API/Store/Hook - 后端: wechat_handler, wechat_service, wechat_user entity, analytics handler, ai_workflow_seed - 配置: WechatConfig, AppConfig.wechat, AuthState wechat 字段 - 启动: 微信凭据检查块, ensure_ai_workflows() 调用 - 迁移: 新增 m20260613_000170_drop_wechat_users.rs - 脚本: api_test_health_alert.py, api_test_mp.py, mpsync.sh/ps1 - E2E: health-data page, flows/ 目录 保留: erp-core/auth/workflow/message/config/plugin + 基座前端 + 通用组件
This commit is contained in:
252
crates/erp-workflow/src/dto.rs
Normal file
252
crates/erp-workflow/src/dto.rs
Normal file
@@ -0,0 +1,252 @@
|
||||
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, Validate, ToSchema)]
|
||||
pub struct ServiceTaskConfig {
|
||||
/// 请求 URL(仅允许 http/https 协议,禁止内网地址)
|
||||
#[validate(length(min = 1, max = 2048), custom(function = "validate_service_url"))]
|
||||
pub url: String,
|
||||
/// HTTP 方法(GET / POST),默认 GET
|
||||
#[serde(default = "default_method")]
|
||||
#[validate(custom(function = "validate_http_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()
|
||||
}
|
||||
|
||||
fn validate_service_url(value: &str) -> Result<(), validator::ValidationError> {
|
||||
if !value.starts_with("https://") && !value.starts_with("http://") {
|
||||
return Err(validator::ValidationError::new("invalid_url_scheme"));
|
||||
}
|
||||
if value.contains("127.0.0.1") || value.contains("localhost") || value.contains("0.0.0.0") {
|
||||
return Err(validator::ValidationError::new("ssrf_blocked"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_http_method(value: &str) -> Result<(), validator::ValidationError> {
|
||||
match value {
|
||||
"GET" | "POST" => Ok(()),
|
||||
_ => Err(validator::ValidationError::new("invalid_http_method")),
|
||||
}
|
||||
}
|
||||
|
||||
/// 流程图连线定义
|
||||
#[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,
|
||||
}
|
||||
Reference in New Issue
Block a user