Skip to main content

openlark_workflow/v2/task/subtask/
create.rs

1//! 创建子任务
2//!
3//! docPath: https://open.feishu.cn/document/server-docs/docs/task-v2/task-subtask/create
4
5use crate::common::{api_endpoints::TaskApiV2, api_utils::*};
6use openlark_core::{
7    api::{ApiRequest, ApiResponseTrait, ResponseFormat},
8    config::Config,
9    validate_required, SDKResult,
10};
11use serde::{Deserialize, Serialize};
12use std::sync::Arc;
13
14/// 创建子任务请求体
15#[derive(Debug, Clone, Serialize, Default)]
16pub struct CreateSubtaskBody {
17    /// 子任务标题
18    pub summary: String,
19
20    /// 子任务描述
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub description: Option<String>,
23
24    /// 子任务执行者
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub assignee: Option<String>,
27
28    /// 子任务截止时间
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub due: Option<String>,
31
32    /// 子任务完成时间
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub completed_at: Option<String>,
35}
36
37/// 创建子任务响应
38#[derive(Debug, Clone, Deserialize)]
39pub struct CreateSubtaskResponse {
40    /// 子任务 GUID
41    pub task_guid: String,
42
43    /// 子任务标题
44    pub summary: String,
45
46    /// 子任务描述
47    #[serde(default)]
48    pub description: Option<String>,
49
50    /// 子任务状态
51    pub status: String,
52
53    /// 父任务 GUID
54    pub parent_task_guid: String,
55
56    /// 创建时间
57    pub created_at: String,
58
59    /// 更新时间
60    pub updated_at: String,
61}
62
63/// 创建子任务请求
64#[derive(Debug, Clone)]
65pub struct CreateSubtaskRequest {
66    /// 配置信息
67    config: Arc<Config>,
68    /// 父任务 GUID
69    task_guid: String,
70    /// 请求体
71    body: CreateSubtaskBody,
72}
73
74impl CreateSubtaskRequest {
75    pub fn new(config: Arc<Config>, task_guid: impl Into<String>) -> Self {
76        Self {
77            config,
78            task_guid: task_guid.into(),
79            body: CreateSubtaskBody::default(),
80        }
81    }
82
83    /// 设置子任务标题
84    pub fn summary(mut self, summary: impl Into<String>) -> Self {
85        self.body.summary = summary.into();
86        self
87    }
88
89    /// 设置子任务描述
90    pub fn description(mut self, description: impl Into<String>) -> Self {
91        self.body.description = Some(description.into());
92        self
93    }
94
95    /// 设置子任务执行者
96    pub fn assignee(mut self, assignee: impl Into<String>) -> Self {
97        self.body.assignee = Some(assignee.into());
98        self
99    }
100
101    /// 设置子任务截止时间
102    pub fn due(mut self, due: impl Into<String>) -> Self {
103        self.body.due = Some(due.into());
104        self
105    }
106
107    /// 设置子任务完成时间
108    pub fn completed_at(mut self, completed_at: impl Into<String>) -> Self {
109        self.body.completed_at = Some(completed_at.into());
110        self
111    }
112
113    /// 执行请求
114    pub async fn execute(self) -> SDKResult<CreateSubtaskResponse> {
115        self.execute_with_options(openlark_core::req_option::RequestOption::default())
116            .await
117    }
118
119    /// 执行请求(带选项)
120    pub async fn execute_with_options(
121        self,
122        option: openlark_core::req_option::RequestOption,
123    ) -> SDKResult<CreateSubtaskResponse> {
124        // 验证必填字段
125        validate_required!(self.body.summary.trim(), "子任务标题不能为空");
126        validate_required!(self.task_guid.trim(), "父任务 GUID 不能为空");
127
128        let api_endpoint = TaskApiV2::SubtaskCreate(self.task_guid.clone());
129        let mut request = ApiRequest::<CreateSubtaskResponse>::post(api_endpoint.to_url());
130
131        let request_body = &self.body;
132        request = request.body(serialize_params(request_body, "创建子任务")?);
133
134        let response =
135            openlark_core::http::Transport::request(request, &self.config, Some(option)).await?;
136        extract_response_data(response, "创建子任务")
137    }
138}
139
140impl ApiResponseTrait for CreateSubtaskResponse {
141    fn data_format() -> ResponseFormat {
142        ResponseFormat::Data
143    }
144}
145
146#[cfg(test)]
147#[allow(unused_imports)]
148mod tests {
149    use std::sync::Arc;
150
151    use super::*;
152
153    #[test]
154    fn test_create_subtask_builder() {
155        let config = Arc::new(
156            openlark_core::config::Config::builder()
157                .app_id("test")
158                .app_secret("test")
159                .build(),
160        );
161
162        let request = CreateSubtaskRequest::new(config, "parent_task_123")
163            .summary("测试子任务")
164            .description("子任务描述")
165            .assignee("user_123");
166
167        assert_eq!(request.task_guid, "parent_task_123");
168        assert_eq!(request.body.summary, "测试子任务");
169        assert_eq!(request.body.description, Some("子任务描述".to_string()));
170        assert_eq!(request.body.assignee, Some("user_123".to_string()));
171    }
172
173    #[test]
174    fn test_subtask_api_v2_url() {
175        let endpoint = TaskApiV2::SubtaskCreate("task_123".to_string());
176        assert_eq!(
177            endpoint.to_url(),
178            "/open-apis/task/v2/tasks/task_123/subtasks"
179        );
180    }
181}