1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub enum MenuButtonType {
7 Click,
8 View,
9 #[serde(rename = "scancode_push")]
10 ScancodePush,
11 #[serde(rename = "scancode_waitmsg")]
12 ScancodeWaitmsg,
13 #[serde(rename = "pic_sysphoto")]
14 PicSysphoto,
15 #[serde(rename = "pic_photo_or_album")]
16 PicPhotoOrAlbum,
17 #[serde(rename = "pic_weixin")]
18 PicWeixin,
19 #[serde(rename = "location_select")]
20 LocationSelect,
21 #[serde(rename = "media_id")]
22 MediaId,
23 #[serde(rename = "article_id")]
24 ArticleId,
25 #[serde(rename = "article_view_limited")]
26 ArticleViewLimited,
27 #[serde(rename = "miniprogram")]
28 MiniProgram,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct MenuButton {
34 pub name: String,
36 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
38 pub button_type: Option<String>,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub key: Option<String>,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub url: Option<String>,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub media_id: Option<String>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub article_id: Option<String>,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub appid: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub pagepath: Option<String>,
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub sub_button: Option<Vec<MenuButton>>,
60}
61
62impl MenuButton {
63 pub fn click(name: impl Into<String>, key: impl Into<String>) -> Self {
65 Self {
66 name: name.into(),
67 button_type: Some("click".to_string()),
68 key: Some(key.into()),
69 url: None,
70 media_id: None,
71 article_id: None,
72 appid: None,
73 pagepath: None,
74 sub_button: None,
75 }
76 }
77
78 pub fn view(name: impl Into<String>, url: impl Into<String>) -> Self {
80 Self {
81 name: name.into(),
82 button_type: Some("view".to_string()),
83 key: None,
84 url: Some(url.into()),
85 media_id: None,
86 article_id: None,
87 appid: None,
88 pagepath: None,
89 sub_button: None,
90 }
91 }
92
93 pub fn parent(name: impl Into<String>, sub_buttons: Vec<MenuButton>) -> Self {
95 Self {
96 name: name.into(),
97 button_type: None,
98 key: None,
99 url: None,
100 media_id: None,
101 article_id: None,
102 appid: None,
103 pagepath: None,
104 sub_button: Some(sub_buttons),
105 }
106 }
107
108 pub fn miniprogram(
110 name: impl Into<String>,
111 url: impl Into<String>,
112 appid: impl Into<String>,
113 pagepath: impl Into<String>,
114 ) -> Self {
115 Self {
116 name: name.into(),
117 button_type: Some("miniprogram".to_string()),
118 key: None,
119 url: Some(url.into()),
120 media_id: None,
121 article_id: None,
122 appid: Some(appid.into()),
123 pagepath: Some(pagepath.into()),
124 sub_button: None,
125 }
126 }
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct Menu {
132 pub button: Vec<MenuButton>,
133}
134
135#[derive(Debug, Clone, Deserialize)]
137pub struct GetMenuResponse {
138 pub menu: Option<Menu>,
139 pub conditionalmenu: Option<Vec<ConditionalMenu>>,
140}
141
142#[derive(Debug, Clone, Deserialize, Serialize)]
144pub struct ConditionalMenu {
145 pub button: Vec<MenuButton>,
146 pub matchrule: MatchRule,
147 pub menuid: Option<i64>,
148}
149
150#[derive(Debug, Clone, Deserialize, Serialize, Default)]
152pub struct MatchRule {
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub tag_id: Option<String>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub client_platform_type: Option<String>,
157}