open_lark/card/components/containers/
column_set.rs

1use serde::{Deserialize, Serialize};
2
3use crate::card::{components::CardElement, href::FeishuCardHrefVal};
4
5/// 多列布局的参数
6#[derive(Debug, Serialize, Deserialize)]
7pub struct ColumnSetContainer {
8    /// 多列布局容器的标识,固定取值:column_set。
9    tag: String,
10    /// 各列之间的水平分栏间距。取值:
11    ///
12    /// - default:默认间距,8px
13    /// - small:窄间距,4px
14    /// - large:大间距,12px
15    /// - [0,28px]:自定义间距
16    #[serde(skip_serializing_if = "Option::is_none")]
17    horizontal_spacing: Option<String>,
18    /// 列容器水平对齐的方式。可取值:
19    ///
20    /// left:左对齐
21    /// center:居中对齐
22    /// right:右对齐
23    #[serde(skip_serializing_if = "Option::is_none")]
24    horizontal_align: Option<String>,
25    /// 列的外边距。值的取值范围为 [0,28]px。可选值:
26    ///
27    /// - 单值,如 "10px",表示列的四个外边距都为 10 px。
28    /// - 多值,如 "4px 12px 4px 12px",表示列的上、右、下、左的外边距分别为
29    ///   4px,12px,4px,12px。四个值必填,使用空格间隔。
30    ///
31    /// 注意:首行列的上外边距强制为 0,末行列的下外边距强制为 0。
32    #[serde(skip_serializing_if = "Option::is_none")]
33    margin: Option<String>,
34    /// 移动端和 PC 端的窄屏幕下,各列的自适应方式。取值:
35    ///
36    /// - none:不做布局上的自适应,在窄屏幕下按比例压缩列宽度。
37    /// - stretch:列布局变为行布局,且每列(行)宽度强制拉伸为 100%,所有列自适应为上下堆叠排布。
38    /// - flow:列流式排布(自动换行),当一行展示不下一列时,自动换至下一行展示。
39    /// - bisect:两列等分布局。
40    /// - trisect:三列等分布局。
41    ///
42    /// 默认值:none。
43    flex_mode: String,
44    /// 分栏的背景色样式。可取值:
45    ///
46    /// default:默认的白底样式,客户端深色主题下为黑底样式
47    /// 卡片支持的颜色枚举值和 RGBA 语法自定义颜色。参考颜色枚举值。
48    /// 注意:当存在分栏的嵌套时,上层分栏的颜色覆盖下层分栏的颜色。
49    #[serde(skip_serializing_if = "Option::is_none")]
50    background_style: Option<String>,
51    /// 多列布局容器内,各个列容器的配置信息
52    columns: Vec<Column>,
53    /// 设置点击分栏时的交互配置。当前仅支持跳转交互。如果布局容器内有交互组件,
54    /// 则优先响应交互组件定义的交互。
55    #[serde(skip_serializing_if = "Option::is_none")]
56    action: Option<ColumnAction>,
57}
58
59impl Default for ColumnSetContainer {
60    fn default() -> Self {
61        ColumnSetContainer {
62            tag: "column_set".to_string(),
63            background_style: None,
64            horizontal_spacing: None,
65            horizontal_align: None,
66            columns: vec![],
67            margin: None,
68            flex_mode: "".to_string(),
69            action: None,
70        }
71    }
72}
73
74impl ColumnSetContainer {
75    pub fn new() -> Self {
76        ColumnSetContainer::default()
77    }
78
79    pub fn horizontal_spacing(mut self, horizontal_spacing: impl ToString) -> Self {
80        self.horizontal_spacing = Some(horizontal_spacing.to_string());
81        self
82    }
83
84    pub fn horizontal_align(mut self, horizontal_align: impl ToString) -> Self {
85        self.horizontal_align = Some(horizontal_align.to_string());
86        self
87    }
88
89    pub fn margin(mut self, margin: impl ToString) -> Self {
90        self.margin = Some(margin.to_string());
91        self
92    }
93
94    pub fn flex_mode(mut self, flex_mode: impl ToString) -> Self {
95        self.flex_mode = flex_mode.to_string();
96        self
97    }
98
99    pub fn background_style(mut self, background_style: impl ToString) -> Self {
100        self.background_style = Some(background_style.to_string());
101        self
102    }
103
104    pub fn columns(mut self, columns: Vec<Column>) -> Self {
105        self.columns = columns;
106        self
107    }
108
109    pub fn action(mut self, action: ColumnAction) -> Self {
110        self.action = Some(action);
111        self
112    }
113}
114
115/// 分栏中列column
116#[derive(Debug, Serialize, Deserialize)]
117pub struct Column {
118    /// 列的标签,固定取值为 column。
119    tag: String,
120    /// 列的背景色样式。可取值:
121    ///
122    /// - default:默认的白底样式,客户端深色主题下为黑底样式
123    /// - 卡片支持的颜色枚举值和 RGBA 语法自定义颜色。参考颜色枚举值
124    #[serde(skip_serializing_if = "Option::is_none")]
125    background_style: Option<String>,
126    /// 列宽度。仅 flex_mode 为 none 时,生效此属性。取值:
127    ///
128    /// auto:列宽度与列内元素宽度一致
129    /// weighted:列宽度按 weight 参数定义的权重分布
130    /// 具体数值,如 100px。取值范围为 [16,600]px。V7.4 及以上版本支持该枚举
131    #[serde(skip_serializing_if = "Option::is_none")]
132    width: Option<String>,
133    /// 当 width 字段取值为 weighted 时生效,表示当前列的宽度占比。取值范围为 1 ~ 5 之间的整数。\
134    #[serde(skip_serializing_if = "Option::is_none")]
135    weight: Option<u32>,
136    /// 列垂直居中的方式。可取值:
137    ///
138    /// - top:上对齐
139    /// - center:居中对齐
140    /// - bottom:下对齐
141    #[serde(skip_serializing_if = "Option::is_none")]
142    vertical_align: Option<String>,
143    /// 列内组件的纵向间距。取值:
144    ///
145    /// - default:默认间距,8px
146    /// - medium:中等间距
147    /// - large:大间距
148    /// - 具体数值,如 8px。取值范围为 [0,28]px
149    #[serde(skip_serializing_if = "Option::is_none")]
150    vertical_spacing: Option<String>,
151    /// 列的内边距。值的取值范围为 [0,28]px。可选值:
152    ///
153    /// - 单值,如 "10px",表示列的四个外边距都为 10 px。
154    /// - 多值,如 "4px 12px 4px 12px",表示列的上、右、下、左的外边距分别为
155    ///   4px,12px,4px,12px。四个值必填,使用空格间隔。
156    #[serde(skip_serializing_if = "Option::is_none")]
157    padding: Option<String>,
158    /// 列容器中内嵌的组件。可内嵌组件参考上文嵌套关系
159    elements: Vec<CardElement>,
160    /// 设置点击列时的交互配置。当前仅支持跳转交互。如果布局容器内有交互组件,
161    /// 则优先响应交互组件定义的交互。
162    #[serde(skip_serializing_if = "Option::is_none")]
163    action: Option<ColumnAction>,
164}
165
166impl Default for Column {
167    fn default() -> Self {
168        Column {
169            tag: "column".to_string(),
170            background_style: None,
171            width: None,
172            weight: None,
173            vertical_align: None,
174            vertical_spacing: None,
175            padding: None,
176            elements: vec![],
177            action: None,
178        }
179    }
180}
181
182impl Column {
183    pub fn new() -> Self {
184        Self::default()
185    }
186
187    pub fn background_style(mut self, background_style: impl ToString) -> Self {
188        self.background_style = Some(background_style.to_string());
189        self
190    }
191
192    pub fn width(mut self, width: impl ToString) -> Self {
193        self.width = Some(width.to_string());
194        self
195    }
196
197    pub fn weight(mut self, weight: u32) -> Self {
198        self.weight = Some(weight);
199        self
200    }
201
202    pub fn vertical_align(mut self, vertical_align: impl ToString) -> Self {
203        self.vertical_align = Some(vertical_align.to_string());
204        self
205    }
206
207    pub fn vertical_spacing(mut self, vertical_spacing: impl ToString) -> Self {
208        self.vertical_spacing = Some(vertical_spacing.to_string());
209        self
210    }
211
212    pub fn padding(mut self, padding: impl ToString) -> Self {
213        self.padding = Some(padding.to_string());
214        self
215    }
216
217    pub fn elements(mut self, elements: Vec<CardElement>) -> Self {
218        self.elements = elements;
219        self
220    }
221
222    pub fn action(mut self, action: ColumnAction) -> Self {
223        self.action = Some(action);
224        self
225    }
226}
227
228/// 设置点击分栏时的交互配置。当前仅支持跳转交互。如果布局容器内有交互组件,
229/// 则优先响应交互组件定义的交互。
230#[derive(Debug, Serialize, Deserialize, Default)]
231pub struct ColumnAction {
232    /// 配置各个端的链接地址。
233    #[serde(skip_serializing_if = "Option::is_none")]
234    multi_url: Option<FeishuCardHrefVal>,
235}
236
237impl ColumnAction {
238    pub fn new() -> Self {
239        Self::default()
240    }
241
242    pub fn multi_url(mut self, multi_url: FeishuCardHrefVal) -> Self {
243        self.multi_url = Some(multi_url);
244        self
245    }
246}
247
248#[cfg(test)]
249mod test {
250    use serde_json::json;
251
252    use crate::card::{
253        components::containers::column_set::{Column, ColumnAction, ColumnSetContainer},
254        href::FeishuCardHrefVal,
255    };
256
257    #[test]
258    fn test_column_set() {
259        let column_set = ColumnSetContainer::new()
260            .horizontal_spacing("large")
261            .horizontal_align("left")
262            .margin("0px")
263            .flex_mode("none")
264            .background_style("default")
265            .action(
266                ColumnAction::new().multi_url(
267                    FeishuCardHrefVal::new()
268                        .url("https://open.feishu.cn")
269                        .pc_url("https://open.feishu.com")
270                        .ios_url("https://developer.apple.com/")
271                        .android_url("https://developer.android.com/"),
272                ),
273            )
274            .columns(vec![Column::new()
275                .background_style("default")
276                .width("auto")
277                .weight(1)
278                .vertical_align("center")
279                .vertical_spacing("4px")
280                .padding("8px")
281                .action(
282                    ColumnAction::new().multi_url(
283                        FeishuCardHrefVal::new()
284                            .url("https://www.baidu.com")
285                            .pc_url("https://www.baidu.com")
286                            .ios_url("https://www.google.com")
287                            .android_url("https://www.apple.com.cn"),
288                    ),
289                )]);
290
291        let expect = json!({
292          "tag": "column_set", // 分栏的标签。
293          "horizontal_spacing": "large", // 分栏中列容器之间的间距。默认值 default(为 8px)。
294          "horizontal_align": "left", // 列容器水平对齐的方式。默认值 left。
295          "margin": "0px", // 列容器的外边距。
296          "flex_mode": "none", // 移动端和 PC 端的窄屏幕下,各列的自适应方式。默认值 none。
297          "background_style": "default", // 分栏的背景色样式。默认值 default。
298          "action": { // 在此处设置点击分栏时的交互配置。
299            "multi_url": {
300              "url": "https://open.feishu.cn",
301              "pc_url": "https://open.feishu.com",
302              "ios_url": "https://developer.apple.com/",
303              "android_url": "https://developer.android.com/"
304            }
305          },
306          "columns": [
307            // 列配置
308            {
309              "tag": "column",
310              "background_style": "default", // 列的背景色样式。默认值 default。
311              "width": "auto", // 列容器的宽度。默认值 auto。
312              "weight": 1, // 当 width 取值 weighted 时生效,表示当前列的宽度占比。
313              "vertical_align": "center", // 列垂直居中的方式。
314              "vertical_spacing": "4px", // 列内子组件纵向间距。默认值 default(8px)。
315              "padding": "8px", // 列容器的内边距。默认值 0px。
316              "action": {
317                // 在此处设置点击列时的交互配置。
318                "multi_url": {
319                  "url": "https://www.baidu.com",
320                  "pc_url": "https://www.baidu.com",
321                  "ios_url": "https://www.google.com",
322                  "android_url": "https://www.apple.com.cn"
323                }
324              },
325              "elements": [] // 列容器内嵌的组件,不支持内嵌表格组件、多图混排组件和表单容器。
326            }
327          ]
328        });
329
330        assert_eq!(json!(column_set), expect);
331    }
332}