labrador/wechat/miniapp/api/
message.rs

1use serde::{Serialize, Deserialize};
2use serde_json::{ Value};
3
4use crate::{session::SessionStore, request::{RequestType}, WechatCommonResponse, LabradorResult};
5use crate::wechat::constants::{KEFU_MSGTYPE_IMAGE, KEFU_MSGTYPE_MA_PAGE, KEFU_MSGTYPE_TEXT};
6use crate::wechat::miniapp::method::{MaMessageMethod, WechatMaMethod};
7use crate::wechat::miniapp::WechatMaClient;
8
9
10/// 消息发送接口.
11#[derive(Debug, Clone)]
12pub struct WechatMaMessage<'a, T: SessionStore> {
13    client: &'a WechatMaClient<T>,
14}
15
16#[allow(unused)]
17impl<'a, T: SessionStore> WechatMaMessage<'a, T> {
18
19    #[inline]
20    pub fn new(client: &WechatMaClient<T>) -> WechatMaMessage<T> {
21        WechatMaMessage {
22            client,
23        }
24    }
25
26
27    /// <pre>
28    /// 发送客服消息
29    /// 详情请见: <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/customerServiceMessage.send.html">发送客服消息</a>
30    /// 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
31    /// </pre>
32    pub async fn send_kefu_msg(&self, message: WxMaKefuMsgRequest) -> LabradorResult<WechatCommonResponse> {
33        self.client.post(WechatMaMethod::Message(MaMessageMethod::SendCustomMsg), vec![], &message, RequestType::Json).await?.json::<WechatCommonResponse>()
34    }
35
36    /// <pre>
37    /// 发送订阅消息
38    /// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
39    /// </pre>
40    pub async fn send_subscribe_msg(&self, data: WxMaSubscribeMsgRequest) -> LabradorResult<WechatCommonResponse> {
41        self.client.post(WechatMaMethod::Message(MaMessageMethod::SendSubscribeMsg), vec![], data, RequestType::Json).await?.json::<WechatCommonResponse>()
42    }
43
44    /// <pre>
45    /// 下发小程序和公众号统一的服务消息
46    /// 详情请见: <a href="https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html">下发小程序和公众号统一的服务消息</a>
47    /// 接口url格式:https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
48    /// </pre>
49    pub async fn send_uniform_msg(&self, data: WxMaUniformMsgRequest) -> LabradorResult<WechatCommonResponse> {
50        self.client.post(WechatMaMethod::Message(MaMessageMethod::SendUniformTemplate), vec![], &data, RequestType::Json).await?.json::<WechatCommonResponse>()
51    }
52
53    /// <pre>
54    ///  创建被分享动态消息的 activity_id.
55    ///  动态消息: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share/updatable-message.html
56    ///
57    ///  文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/updatable-message/updatableMessage.createActivityId.html
58    ///  接口地址:GET https://api.weixin.qq.com/cgi-bin/message/wxopen/activityid/create?access_token=ACCESS_TOKEN
59    /// </pre>
60    pub async fn create_updatable_message_activity_id<D: Serialize>(&self, data: D) -> LabradorResult<Value> {
61        self.client.get(WechatMaMethod::Message(MaMessageMethod::CreateActivityId), vec![], RequestType::Json).await?.json::<serde_json::Value>()
62    }
63
64    /// <pre>
65    ///  修改被分享的动态消息.
66    ///  动态消息: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share/updatable-message.html
67    ///
68    ///  文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/updatable-message/updatableMessage.setUpdatableMsg.html
69    ///  接口地址:POST https://api.weixin.qq.com/cgi-bin/message/wxopen/activityid/create?access_token=ACCESS_TOKEN
70    /// </pre>
71    pub async fn create_updatable_message<D: Serialize>(&self, data: D) -> LabradorResult<()> {
72        self.client.post(WechatMaMethod::Message(MaMessageMethod::SendUpdatableMsg), vec![], data, RequestType::Json).await?.json::<serde_json::Value>()?;
73        Ok(())
74    }
75}
76
77
78//----------------------------------------------------------------------------------------------------------------------------
79
80/// 客服消息
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct WxMaKefuMsgRequest {
83    pub touser: String,
84    pub msgtype: String,
85    pub text: Option<KfText>,
86    pub image: Option<KfImage>,
87    pub link: Option<KfLink>,
88    pub miniprogrampage: Option<KfMaPage>,
89}
90
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct KfText {
94    pub content: Option<String>,
95}
96
97#[allow(unused)]
98impl KfText {
99
100    pub fn new() -> Self {
101        Self {
102            content: None,
103        }
104    }
105
106    fn content(mut self, content: &str) -> Self {
107        self.content = content.to_string().into();
108        self
109    }
110
111    pub fn build_msg(self) -> WxMaKefuMsgRequest {
112        WxMaKefuMsgRequest {
113            touser: "".to_string(),
114            msgtype: KEFU_MSGTYPE_TEXT.to_string(),
115            text: self.into(),
116            image: None,
117            link: None,
118            miniprogrampage: None
119        }
120    }
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct KfImage {
125    pub media_id: Option<String>,
126}
127
128#[allow(unused)]
129impl KfImage {
130
131    pub fn new() -> Self {
132        Self {
133            media_id: None,
134        }
135    }
136
137    fn media_id(mut self, media_id: &str) -> Self {
138        self.media_id = media_id.to_string().into();
139        self
140    }
141
142    pub fn build_msg(self) -> WxMaKefuMsgRequest {
143        WxMaKefuMsgRequest {
144            touser: "".to_string(),
145            msgtype: KEFU_MSGTYPE_IMAGE.to_string(),
146            text: None,
147            image: self.into(),
148            link: None,
149            miniprogrampage: None
150        }
151    }
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct KfLink {
156    pub title: Option<String>,
157    pub description: Option<String>,
158    pub thumb_url: Option<String>,
159    pub url: Option<String>,
160}
161
162#[allow(unused)]
163impl KfLink {
164
165    pub fn new() -> Self {
166        Self {
167            title: None,
168            description: None,
169            thumb_url: None,
170            url: None
171        }
172    }
173
174    fn url(mut self, url: &str) -> Self {
175        self.url = url.to_string().into();
176        self
177    }
178    fn title(mut self, title: &str) -> Self {
179        self.title = title.to_string().into();
180        self
181    }
182    fn thumb_url(mut self, thumb_url: &str) -> Self {
183        self.thumb_url = thumb_url.to_string().into();
184        self
185    }
186    fn description(mut self, description: &str) -> Self {
187        self.description = description.to_string().into();
188        self
189    }
190
191    pub fn build_msg(self) -> WxMaKefuMsgRequest {
192        WxMaKefuMsgRequest {
193            touser: "".to_string(),
194            msgtype: KEFU_MSGTYPE_IMAGE.to_string(),
195            text: None,
196            image: None,
197            link: self.into(),
198            miniprogrampage: None
199        }
200    }
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct KfMaPage {
205    pub title: Option<String>,
206    pub pagepath: Option<String>,
207    pub thumb_media_id: Option<String>,
208}
209
210#[allow(unused)]
211impl KfMaPage {
212
213    pub fn new() -> Self {
214        Self {
215            title: None,
216            pagepath: None,
217            thumb_media_id: None
218        }
219    }
220    
221    fn thumb_media_id(mut self, thumb_media_id: &str) -> Self {
222        self.thumb_media_id = thumb_media_id.to_string().into();
223        self
224    }
225    fn pagepath(mut self, pagepath: &str) -> Self {
226        self.pagepath = pagepath.to_string().into();
227        self
228    }
229    fn title(mut self, title: &str) -> Self {
230        self.title = title.to_string().into();
231        self
232    }
233
234    pub fn build_msg(self) -> WxMaKefuMsgRequest {
235        WxMaKefuMsgRequest {
236            touser: "".to_string(),
237            msgtype: KEFU_MSGTYPE_MA_PAGE.to_string(),
238            text: None,
239            image: None,
240            link: None,
241            miniprogrampage: self.into()
242        }
243    }
244}
245
246#[allow(unused)]
247impl WxMaKefuMsgRequest {
248
249    fn touser(mut self, touser: &str) -> Self {
250        self.touser = touser.to_string().into();
251        self
252    }
253
254    fn text() -> KfText {
255        KfText::new()
256    }
257
258    fn image() -> KfImage {
259        KfImage::new()
260    }
261
262    fn link() -> KfLink {
263        KfLink::new()
264    }
265
266    fn miniprogram() -> KfMaPage {
267        KfMaPage::new()
268    }
269}
270
271
272
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct WxMaSubscribeMsgRequest {
276    /// 接收者(用户)的 openid.
277    /// <pre>
278    /// 参数:touser
279    /// 是否必填: 是
280    /// 描述: 接收者(用户)的 openid
281    /// </pre>
282    pub touser: String,
283    /// 所需下发的模板消息的id.
284    /// <pre>
285    /// 参数:template_id
286    /// 是否必填: 是
287    /// 描述: 所需下发的模板消息的id
288    /// </pre>
289    pub template_id: String,
290    /// 点击模板卡片后的跳转页面,仅限本小程序内的页面.
291    /// <pre>
292    /// 参数:page
293    /// 是否必填: 否
294    /// 描述: 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
295    /// </pre>
296    pub page: Option<String>,
297    /// 模板内容,不填则下发空模板.
298    /// <pre>
299    /// 参数:data
300    /// 是否必填: 是
301    /// 描述: 模板内容,不填则下发空模板
302    /// </pre>
303    pub data: Option<Value>,
304    /// 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
305    pub miniprogram_state: Option<String>,
306    /// 进入小程序查看的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN
307    pub lang: Option<String>,
308}
309
310
311#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct WxMaUniformMsgRequest {
313    touser: String,
314    /// 小程序模板消息相关的信息,可以参考小程序模板消息接口; 有此节点则优先发送小程序模板消息;(小程序模板消息已下线,不用传此节点)
315    weapp_template_msg: Option<WeappTemplateMsg>,
316    /// 公众号模板消息相关的信息,可以参考公众号模板消息接口;有此节点并且没有weapp_template_msg节点时,发送公众号模板消息
317    mp_template_msg: MpTemplateMsg,
318}
319
320#[derive(Debug, Clone,Deserialize, Serialize)]
321pub struct MsgData {
322    name: String,
323    value: String,
324}
325
326
327#[derive(Debug, Clone,Serialize, Deserialize)]
328pub struct WeappTemplateMsg {
329    template_id: String,
330    page: String,
331    form_id: String,
332    data: Value,
333    /// 小程序模板放大关键词
334    emphasis_keyword: String,
335}
336
337
338#[allow(unused)]
339impl WxMaUniformMsgRequest {
340    pub fn new<S: Into<String>>(touser: S, weapp_template_msg:  Option<WeappTemplateMsg>, mp_template_msg:MpTemplateMsg) -> WxMaUniformMsgRequest {
341        WxMaUniformMsgRequest {
342            touser: touser.into(),
343            weapp_template_msg,
344            mp_template_msg,
345            
346        }
347    }
348}
349
350
351#[derive(Debug, Clone,Serialize, Deserialize)]
352pub struct MpTemplateMsg {
353    appid: String,
354    template_id: String,
355    url: String,
356    miniprogram: Value,
357    data: Value,
358}