rust_viewflow/core/workflows/
leave_request.rs1use async_trait::async_trait;
2use chrono;
3use serde_json;
4use std::sync::Arc;
5
6use crate::core::engine::generate_id;
7use crate::core::{
8 TaskState, TaskStatus, WorkflowDefinition, WorkflowResult, WorkflowState, WorkflowStatus,
9};
10use crate::db::WorkflowDatabase;
11
12pub struct LeaveRequestWorkflow {
14 database: Arc<dyn WorkflowDatabase>,
15}
16
17impl LeaveRequestWorkflow {
18 pub fn new(database: Arc<dyn WorkflowDatabase>) -> Self {
19 Self { database }
20 }
21
22 fn task_name(locale: &str, stage: &str) -> &'static str {
23 match (locale, stage) {
24 ("zh-CN", "manager") => "直属经理审批",
25 ("zh-CN", "hr") => "HR 备案",
26 ("zh-TW", "manager") => "直屬主管審批",
27 ("zh-TW", "hr") => "HR 備案",
28 (_, "manager") => "Manager Approval",
29 (_, "hr") => "HR Approval",
30 _ => "Task",
31 }
32 }
33}
34
35#[async_trait]
36impl WorkflowDefinition for LeaveRequestWorkflow {
37 fn name(&self) -> &str {
38 "leave_request"
39 }
40
41 async fn start(&self, data: serde_json::Value) -> WorkflowResult<WorkflowState> {
42 let now = chrono::Utc::now();
43 let workflow_id = generate_id();
44 let locale = data.get("locale").and_then(|v| v.as_str()).unwrap_or("en");
45
46 let workflow = WorkflowState {
47 id: workflow_id.clone(),
48 name: self.name().to_string(),
49 status: WorkflowStatus::Running,
50 data: data.clone(),
51 created_at: now,
52 updated_at: now,
53 };
54
55 self.database.create_workflow(&workflow).await?;
56
57 let manager_task = TaskState {
58 id: generate_id(),
59 workflow_id: workflow_id.clone(),
60 name: Self::task_name(locale, "manager").to_string(),
61 status: TaskStatus::Pending,
62 assignee: data
63 .get("manager_id")
64 .and_then(|v| v.as_str())
65 .map(|s| s.to_string()),
66 data: data.clone(),
67 created_at: now,
68 updated_at: now,
69 completed_at: None,
70 };
71
72 self.database.create_task(&manager_task).await?;
73
74 Ok(workflow)
75 }
76
77 async fn execute_task(
78 &self,
79 task_id: &str,
80 data: serde_json::Value,
81 ) -> WorkflowResult<TaskState> {
82 let mut task = self.database.get_task(task_id).await?;
83 let locale = data
84 .get("locale")
85 .and_then(|v| v.as_str())
86 .or_else(|| task.data.get("locale").and_then(|v| v.as_str()))
87 .unwrap_or("en");
88
89 if data
90 .get("approved")
91 .and_then(|v| v.as_bool())
92 .unwrap_or(false)
93 {
94 task.status = TaskStatus::Completed;
95 task.completed_at = Some(chrono::Utc::now());
96
97 if task.name.contains("Manager")
98 || task.name.contains("经理")
99 || task.name.contains("主管")
100 {
101 let hr_task = TaskState {
102 id: generate_id(),
103 workflow_id: task.workflow_id.clone(),
104 name: Self::task_name(locale, "hr").to_string(),
105 status: TaskStatus::Pending,
106 assignee: data
107 .get("hr_id")
108 .and_then(|v| v.as_str())
109 .map(|s| s.to_string())
110 .or_else(|| Some("hr@example.com".to_string())),
111 data: data.clone(),
112 created_at: chrono::Utc::now(),
113 updated_at: chrono::Utc::now(),
114 completed_at: None,
115 };
116 self.database.create_task(&hr_task).await?;
117 } else {
118 let mut workflow = self.database.get_workflow(&task.workflow_id).await?;
119 workflow.status = WorkflowStatus::Completed;
120 workflow.updated_at = chrono::Utc::now();
121 self.database.update_workflow(&workflow).await?;
122 }
123 } else {
124 task.status = TaskStatus::Cancelled;
125 task.completed_at = Some(chrono::Utc::now());
126
127 let mut workflow = self.database.get_workflow(&task.workflow_id).await?;
128 workflow.status = WorkflowStatus::Cancelled;
129 workflow.updated_at = chrono::Utc::now();
130 self.database.update_workflow(&workflow).await?;
131 }
132
133 task.data = data;
134 task.updated_at = chrono::Utc::now();
135
136 self.database.update_task(&task).await?;
137
138 Ok(task)
139 }
140
141 async fn get_tasks(&self, workflow_id: &str) -> WorkflowResult<Vec<TaskState>> {
142 self.database.get_tasks_by_workflow(workflow_id).await
143 }
144}