open_lark/service/cloud_docs/bitable/v1/app_table/
create.rs

1use reqwest::Method;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5    core::{
6        api_req::ApiRequest,
7        api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
8        constants::AccessTokenType,
9        http::Transport,
10        req_option::RequestOption,
11        SDKResult,
12    },
13    impl_executable_builder_owned,
14};
15
16use super::AppTableService;
17
18impl AppTableService {
19    /// 新增一个数据表
20    pub async fn create(
21        &self,
22        request: CreateTableRequest,
23        option: Option<RequestOption>,
24    ) -> SDKResult<BaseResponse<CreateTableResponse>> {
25        let mut api_req = request.api_request;
26        api_req.http_method = Method::POST;
27        api_req.api_path = format!("/open-apis/bitable/v1/apps/{}/tables", request.app_token);
28        api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
29        api_req.body = serde_json::to_vec(&CreateTableRequestBody {
30            table: request.table,
31        })?;
32
33        let api_resp = Transport::request(api_req, &self.config, option).await?;
34        Ok(api_resp)
35    }
36}
37
38/// 新增数据表请求
39#[derive(Debug, Default)]
40pub struct CreateTableRequest {
41    api_request: ApiRequest,
42    /// 多维表格的 app_token
43    app_token: String,
44    /// 数据表信息
45    table: TableData,
46}
47
48impl CreateTableRequest {
49    pub fn builder() -> CreateTableRequestBuilder {
50        CreateTableRequestBuilder::default()
51    }
52
53    /// 创建新增数据表请求
54    pub fn new(app_token: impl ToString, table: TableData) -> Self {
55        Self {
56            api_request: ApiRequest::default(),
57            app_token: app_token.to_string(),
58            table,
59        }
60    }
61}
62
63#[derive(Default)]
64pub struct CreateTableRequestBuilder {
65    request: CreateTableRequest,
66}
67
68impl CreateTableRequestBuilder {
69    /// 多维表格的 app_token
70    pub fn app_token(mut self, app_token: impl ToString) -> Self {
71        self.request.app_token = app_token.to_string();
72        self
73    }
74
75    /// 数据表信息
76    pub fn table(mut self, table: TableData) -> Self {
77        self.request.table = table;
78        self
79    }
80
81    pub fn build(self) -> CreateTableRequest {
82        self.request
83    }
84}
85
86impl_executable_builder_owned!(
87    CreateTableRequestBuilder,
88    AppTableService,
89    CreateTableRequest,
90    BaseResponse<CreateTableResponse>,
91    create
92);
93
94/// 数据表数据
95#[derive(Debug, Clone, Default, Serialize, Deserialize)]
96pub struct TableData {
97    /// 数据表名称
98    pub name: String,
99    /// 数据表的默认视图名称,不填则默认为"数据表"
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub default_view_name: Option<String>,
102    /// 数据表初始字段
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub fields: Option<Vec<TableField>>,
105}
106
107impl TableData {
108    /// 创建数据表数据
109    pub fn new(name: impl ToString) -> Self {
110        Self {
111            name: name.to_string(),
112            default_view_name: None,
113            fields: None,
114        }
115    }
116
117    /// 设置默认视图名称
118    pub fn with_default_view_name(mut self, view_name: impl ToString) -> Self {
119        self.default_view_name = Some(view_name.to_string());
120        self
121    }
122
123    /// 设置初始字段
124    pub fn with_fields(mut self, fields: Vec<TableField>) -> Self {
125        self.fields = Some(fields);
126        self
127    }
128}
129
130/// 字段信息
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct TableField {
133    /// 字段名称
134    pub field_name: String,
135    /// 字段类型
136    #[serde(rename = "type")]
137    pub field_type: i32,
138    /// 字段属性,不同字段类型对应不同的属性结构
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub property: Option<serde_json::Value>,
141}
142
143impl TableField {
144    /// 创建文本字段
145    pub fn text(name: impl ToString) -> Self {
146        Self {
147            field_name: name.to_string(),
148            field_type: 1, // 多行文本
149            property: None,
150        }
151    }
152
153    /// 创建数字字段
154    pub fn number(name: impl ToString) -> Self {
155        Self {
156            field_name: name.to_string(),
157            field_type: 2, // 数字
158            property: None,
159        }
160    }
161
162    /// 创建单选字段
163    pub fn single_select(name: impl ToString, options: Vec<String>) -> Self {
164        let options_value: Vec<serde_json::Value> = options
165            .into_iter()
166            .map(|opt| serde_json::json!({"name": opt}))
167            .collect();
168
169        Self {
170            field_name: name.to_string(),
171            field_type: 3, // 单选
172            property: Some(serde_json::json!({"options": options_value})),
173        }
174    }
175
176    /// 创建多选字段
177    pub fn multi_select(name: impl ToString, options: Vec<String>) -> Self {
178        let options_value: Vec<serde_json::Value> = options
179            .into_iter()
180            .map(|opt| serde_json::json!({"name": opt}))
181            .collect();
182
183        Self {
184            field_name: name.to_string(),
185            field_type: 4, // 多选
186            property: Some(serde_json::json!({"options": options_value})),
187        }
188    }
189
190    /// 创建日期字段
191    pub fn date(name: impl ToString) -> Self {
192        Self {
193            field_name: name.to_string(),
194            field_type: 5, // 日期
195            property: None,
196        }
197    }
198}
199
200#[derive(Serialize)]
201struct CreateTableRequestBody {
202    table: TableData,
203}
204
205#[derive(Deserialize, Debug)]
206pub struct CreateTableResponse {
207    /// 数据表信息
208    pub table_id: String,
209    /// 数据表的默认视图 ID
210    pub default_view_id: String,
211    /// 数据表初始字段的 field_id 列表
212    pub field_id_list: Vec<String>,
213}
214
215impl ApiResponseTrait for CreateTableResponse {
216    fn data_format() -> ResponseFormat {
217        ResponseFormat::Data
218    }
219}
220
221#[cfg(test)]
222mod tests {
223    use super::*;
224
225    #[test]
226    fn test_create_table_request() {
227        let table = TableData::new("测试数据表")
228            .with_default_view_name("主视图")
229            .with_fields(vec![
230                TableField::text("标题"),
231                TableField::number("数量"),
232                TableField::single_select("状态", vec!["进行中".to_string(), "已完成".to_string()]),
233            ]);
234
235        let request = CreateTableRequest::builder()
236            .app_token("bascnmBA*****yGehy8")
237            .table(table)
238            .build();
239
240        assert_eq!(request.app_token, "bascnmBA*****yGehy8");
241        assert_eq!(request.table.name, "测试数据表");
242    }
243
244    #[test]
245    fn test_table_field_types() {
246        let text_field = TableField::text("标题");
247        assert_eq!(text_field.field_type, 1);
248        assert_eq!(text_field.field_name, "标题");
249
250        let number_field = TableField::number("数量");
251        assert_eq!(number_field.field_type, 2);
252
253        let select_field =
254            TableField::single_select("状态", vec!["A".to_string(), "B".to_string()]);
255        assert_eq!(select_field.field_type, 3);
256        assert!(select_field.property.is_some());
257    }
258}