CustomApi.cs 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  1. #region Apache License Version 2.0
  2. /*----------------------------------------------------------------
  3. Copyright 2019 Jeffrey Su & Suzhou Senparc Network Technology Co.,Ltd.
  4. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
  5. except in compliance with the License. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software distributed under the
  8. License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  9. either express or implied. See the License for the specific language governing permissions
  10. and limitations under the License.
  11. Detail: https://github.com/JeffreySu/WeiXinMPSDK/blob/master/license.md
  12. ----------------------------------------------------------------*/
  13. #endregion Apache License Version 2.0
  14. /*----------------------------------------------------------------
  15. Copyright (C) 2019 Senparc
  16. 文件名:CustomAPI.cs
  17. 文件功能描述:客服接口
  18. 创建标识:Senparc - 20150211
  19. 修改标识:Senparc - 20150303
  20. 修改描述:整理接口
  21. 修改标识:Senparc - 20150312
  22. 修改描述:开放代理请求超时时间
  23. 修改标识:Senparc - 20160718
  24. 修改描述:增加其接口的异步方法
  25. 修改标识:Senparc - 20160722
  26. 修改描述:将其SendText方法增加了kfAccount的参数
  27. 修改标识:Senparc - 20160802
  28. 修改描述:将其Send方法增加了kfAccount的参数
  29. 创建标识:Senparc - 20160808
  30. 创建描述:增加SendCard
  31. 创建标识:Senparc - 20161224
  32. 创建描述:SendVideo方法添加thumb_media_id参数 感谢 @hello2008zj
  33. 修改标识:Senparc - 20170707
  34. 修改描述:v14.5.1 完善异步方法async/await
  35. 修改标识:Senparc - 20180928
  36. 修改描述:增加GetTypingStatus
  37. 修改标识:Senparc - 20190129
  38. 修改描述:统一 CommonJsonSend.Send<T>() 方法请求接口
  39. ----------------------------------------------------------------*/
  40. /*
  41. API地址:http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html
  42. 新地址(2019年3月):https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140547
  43. */
  44. using Senparc.CO2NET.Extensions;
  45. using Senparc.CO2NET.Helpers.Serializers;
  46. using Senparc.NeuChar;
  47. using Senparc.NeuChar.Entities;
  48. using Senparc.Weixin.CommonAPIs;
  49. using Senparc.Weixin.Entities;
  50. using Senparc.Weixin.MP.CommonAPIs;
  51. using System.Collections.Generic;
  52. using System.Linq;
  53. using System.Threading.Tasks;
  54. namespace Senparc.Weixin.MP.AdvancedAPIs
  55. {
  56. /// <summary>
  57. /// 客服接口
  58. /// </summary>
  59. public static class CustomApi
  60. {
  61. /// <summary>
  62. /// 客服消息统一请求地址格式
  63. /// </summary>
  64. public static readonly string UrlFormat = Config.ApiMpHost + "/cgi-bin/message/custom/send?access_token={0}";
  65. #region 同步方法
  66. /// <summary>
  67. /// 发送文本信息
  68. /// </summary>
  69. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  70. /// <param name="openId"></param>
  71. /// <param name="content"></param>
  72. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  73. /// <param name="kfAccount">客服</param>
  74. /// <returns></returns>
  75. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendText", true)]
  76. public static WxJsonResult SendText(string accessTokenOrAppId, string openId, string content,
  77. int timeOut = Config.TIME_OUT, string kfAccount = "")
  78. {
  79. object data = null;
  80. if (kfAccount.IsNullOrWhiteSpace())
  81. {
  82. data = new
  83. {
  84. touser = openId,
  85. msgtype = "text",
  86. text = new
  87. {
  88. content = content
  89. }
  90. };
  91. }
  92. else
  93. {
  94. data = new
  95. {
  96. touser = openId,
  97. msgtype = "text",
  98. text = new
  99. {
  100. content = content
  101. },
  102. customservice = new
  103. {
  104. kf_account = kfAccount
  105. }
  106. };
  107. }
  108. return ApiHandlerWapper.TryCommonApi(accessToken =>
  109. {
  110. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut);
  111. }, accessTokenOrAppId);
  112. }
  113. /// <summary>
  114. /// 发送图片消息
  115. /// </summary>
  116. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  117. /// <param name="openId"></param>
  118. /// <param name="mediaId"></param>
  119. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  120. /// <param name="kfAccount">客服</param>
  121. /// <returns></returns>
  122. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendImage", true)]
  123. public static WxJsonResult SendImage(string accessTokenOrAppId, string openId, string mediaId, int timeOut = Config.TIME_OUT, string kfAccount = "")
  124. {
  125. object data = null;
  126. if (kfAccount.IsNullOrWhiteSpace())
  127. {
  128. data = new
  129. {
  130. touser = openId,
  131. msgtype = "image",
  132. image = new
  133. {
  134. media_id = mediaId
  135. }
  136. };
  137. }
  138. else
  139. {
  140. data = new
  141. {
  142. touser = openId,
  143. msgtype = "image",
  144. image = new
  145. {
  146. media_id = mediaId
  147. },
  148. CustomService = new
  149. {
  150. kf_account = kfAccount
  151. }
  152. };
  153. }
  154. return ApiHandlerWapper.TryCommonApi(accessToken =>
  155. {
  156. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut);
  157. }, accessTokenOrAppId);
  158. }
  159. /// <summary>
  160. /// 发送语音消息
  161. /// </summary>
  162. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  163. /// <param name="openId"></param>
  164. /// <param name="mediaId"></param>
  165. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  166. /// <param name="kfAccount"></param>
  167. /// <returns></returns>
  168. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendVoice", true)]
  169. public static WxJsonResult SendVoice(string accessTokenOrAppId, string openId, string mediaId, int timeOut = Config.TIME_OUT, string kfAccount = "")
  170. {
  171. object data = null;
  172. if (kfAccount.IsNullOrWhiteSpace())
  173. {
  174. data = new
  175. {
  176. touser = openId,
  177. msgtype = "voice",
  178. voice = new
  179. {
  180. media_id = mediaId
  181. }
  182. };
  183. }
  184. else
  185. {
  186. data = new
  187. {
  188. touser = openId,
  189. msgtype = "voice",
  190. voice = new
  191. {
  192. media_id = mediaId
  193. },
  194. CustomService = new
  195. {
  196. kf_account = kfAccount
  197. }
  198. };
  199. }
  200. return ApiHandlerWapper.TryCommonApi(accessToken =>
  201. {
  202. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut);
  203. }, accessTokenOrAppId);
  204. }
  205. /// <summary>
  206. /// 发送视频消息
  207. /// </summary>
  208. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  209. /// <param name="openId"></param>
  210. /// <param name="mediaId"></param>
  211. /// <param name="title"></param>
  212. /// <param name="description"></param>
  213. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  214. /// <param name="kfAccount">客服</param>
  215. /// <param name="thumb_media_id"></param>
  216. /// <returns></returns>
  217. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendVideo", true)]
  218. public static WxJsonResult SendVideo(string accessTokenOrAppId, string openId, string mediaId, string title, string description, int timeOut = Config.TIME_OUT, string kfAccount = "", string thumb_media_id = "")
  219. {
  220. object data = null;
  221. if (kfAccount.IsNullOrWhiteSpace())
  222. {
  223. data = new
  224. {
  225. touser = openId,
  226. msgtype = "video",
  227. video = new
  228. {
  229. media_id = mediaId,
  230. thumb_media_id = thumb_media_id,
  231. title = title,
  232. description = description
  233. }
  234. };
  235. }
  236. else
  237. {
  238. data = new
  239. {
  240. touser = openId,
  241. msgtype = "video",
  242. video = new
  243. {
  244. media_id = mediaId,
  245. thumb_media_id = thumb_media_id,
  246. title = title,
  247. description = description
  248. },
  249. CustomService = new
  250. {
  251. kf_account = kfAccount
  252. }
  253. };
  254. }
  255. return ApiHandlerWapper.TryCommonApi(accessToken =>
  256. {
  257. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut);
  258. }, accessTokenOrAppId);
  259. }
  260. /// <summary>
  261. /// 发送音乐消息
  262. /// </summary>
  263. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  264. /// <param name="openId"></param>
  265. /// <param name="title">音乐标题(非必须)</param>
  266. /// <param name="description">音乐描述(非必须)</param>
  267. /// <param name="musicUrl">音乐链接</param>
  268. /// <param name="hqMusicUrl">高品质音乐链接,wifi环境优先使用该链接播放音乐</param>
  269. /// <param name="thumbMediaId">视频缩略图的媒体ID</param>
  270. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  271. /// <param name="kfAccount">客服</param>
  272. /// <returns></returns>
  273. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendMusic", true)]
  274. public static WxJsonResult SendMusic(string accessTokenOrAppId, string openId, string title, string description,
  275. string musicUrl, string hqMusicUrl, string thumbMediaId, int timeOut = Config.TIME_OUT, string kfAccount = "")
  276. {
  277. object data = null;
  278. if (kfAccount.IsNullOrWhiteSpace())
  279. {
  280. data = new
  281. {
  282. touser = openId,
  283. msgtype = "music",
  284. music = new
  285. {
  286. title = title,
  287. description = description,
  288. musicurl = musicUrl,
  289. hqmusicurl = hqMusicUrl,
  290. thumb_media_id = thumbMediaId
  291. }
  292. };
  293. }
  294. else
  295. {
  296. data = new
  297. {
  298. touser = openId,
  299. msgtype = "music",
  300. music = new
  301. {
  302. title = title,
  303. description = description,
  304. musicurl = musicUrl,
  305. hqmusicurl = hqMusicUrl,
  306. thumb_media_id = thumbMediaId
  307. },
  308. CustomService = new
  309. {
  310. kf_account = kfAccount
  311. }
  312. };
  313. }
  314. return ApiHandlerWapper.TryCommonApi(accessToken =>
  315. {
  316. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut);
  317. }, accessTokenOrAppId);
  318. }
  319. /// <summary>
  320. /// 发送图文消息(点击跳转到外链)
  321. /// </summary>
  322. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  323. /// <param name="openId"></param>
  324. /// <param name="articles"></param>
  325. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  326. /// <param name="kfAccount">客服</param>
  327. /// <returns></returns>
  328. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendNews", true)]
  329. public static WxJsonResult SendNews(string accessTokenOrAppId, string openId, List<Article> articles, int timeOut = Config.TIME_OUT, string kfAccount = "")
  330. {
  331. object data = null;
  332. if (kfAccount.IsNullOrWhiteSpace())
  333. {
  334. data = new
  335. {
  336. touser = openId,
  337. msgtype = "news",
  338. news = new
  339. {
  340. articles = articles.Select(z => new
  341. {
  342. title = z.Title,
  343. description = z.Description,
  344. url = z.Url,
  345. picurl = z.PicUrl //图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80
  346. }).ToList()
  347. }
  348. };
  349. }
  350. else
  351. {
  352. data = new
  353. {
  354. touser = openId,
  355. msgtype = "news",
  356. news = new
  357. {
  358. articles = articles.Select(z => new
  359. {
  360. title = z.Title,
  361. description = z.Description,
  362. url = z.Url,
  363. picurl = z.PicUrl//图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80
  364. }).ToList()
  365. },
  366. CustomService = new
  367. {
  368. kf_account = kfAccount
  369. }
  370. };
  371. }
  372. return ApiHandlerWapper.TryCommonApi(accessToken =>
  373. {
  374. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut);
  375. }, accessTokenOrAppId);
  376. }
  377. /// <summary>
  378. /// 发送图文消息(点击跳转到图文消息页面)
  379. /// 图文消息条数限制在8条以内,注意,如果图文数超过8,则将会无响应。
  380. /// </summary>
  381. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  382. /// <param name="openId"></param>
  383. /// <param name="mediaId"></param>
  384. /// <param name="timeOut"></param>
  385. /// <param name="kfAccount">客服</param>
  386. /// <returns></returns>
  387. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendMpNews", true)]
  388. public static WxJsonResult SendMpNews(string accessTokenOrAppId, string openId, string mediaId, int timeOut = Config.TIME_OUT, string kfAccount = "")
  389. {
  390. object data = null;
  391. if (kfAccount.IsNullOrWhiteSpace())
  392. {
  393. data = new
  394. {
  395. touser = openId,
  396. msgtype = "mpnews",
  397. mpnews = new
  398. {
  399. media_id = mediaId
  400. }
  401. };
  402. }
  403. else
  404. {
  405. data = new
  406. {
  407. touser = openId,
  408. msgtype = "mpnews",
  409. mpnews = new
  410. {
  411. media_id = mediaId
  412. },
  413. CustomService = new
  414. {
  415. kf_account = kfAccount
  416. }
  417. };
  418. }
  419. return ApiHandlerWapper.TryCommonApi(accessToken =>
  420. {
  421. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut);
  422. }, accessTokenOrAppId);
  423. }
  424. /// <summary>
  425. /// 发送卡券
  426. /// </summary>
  427. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  428. /// <param name="openId"></param>
  429. /// <param name="cardId"></param>
  430. /// <param name="cardExt"></param>
  431. /// <param name="timeOut"></param>
  432. /// <returns></returns>
  433. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendCard", true)]
  434. public static WxJsonResult SendCard(string accessTokenOrAppId, string openId, string cardId, CardExt cardExt, int timeOut = Config.TIME_OUT)
  435. {
  436. return ApiHandlerWapper.TryCommonApi(accessToken =>
  437. {
  438. var data = new
  439. {
  440. touser = openId,
  441. msgtype = "wxcard",
  442. wxcard = new
  443. {
  444. card_id = cardId,
  445. card_ext = cardExt
  446. }
  447. };
  448. JsonSetting jsonSetting = new JsonSetting()
  449. {
  450. TypesToIgnoreNull = new List<System.Type>() { typeof(CardExt) }
  451. };
  452. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut, jsonSetting: jsonSetting);
  453. }, accessTokenOrAppId);
  454. }
  455. /// <summary>
  456. /// 客服输入状态
  457. /// </summary>
  458. /// <param name="accessTokenOrAppId"></param>
  459. /// <param name="cardId"></param>
  460. /// <param name="typingStatus"></param>
  461. /// <param name="timeOut"></param>
  462. /// <returns></returns>
  463. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.GetTypingStatus", true)]
  464. public static WxJsonResult GetTypingStatus(string accessTokenOrAppId, string cardId, string typingStatus, int timeOut = Config.TIME_OUT)
  465. {
  466. return ApiHandlerWapper.TryCommonApi(accessToken =>
  467. {
  468. var urlFormat = string.Format(Config.ApiMpHost + "/cgi-bin/message/custom/typing?access_token={0}", accessToken.AsUrlData());
  469. var data = new
  470. {
  471. touser = cardId,
  472. command = typingStatus
  473. };
  474. return CommonJsonSend.Send<WxJsonResult>(null, urlFormat, data, timeOut: timeOut);
  475. }, accessTokenOrAppId);
  476. }
  477. /// <summary>
  478. /// 发送客户菜单消息
  479. /// </summary>
  480. /// <param name="accessTokenOrAppId"></param>
  481. /// <param name="openId">接受人员OPenid</param>
  482. /// <param name="head">标题</param>
  483. /// <param name="menuList">内容</param>
  484. /// <param name="tail">结尾内容</param>
  485. /// <param name="timeOut">超时时间</param>
  486. /// <returns></returns>
  487. public static WxJsonResult SendMenu(string accessTokenOrAppId, string openId,
  488. string head, List<SendMenuContent> menuList, string tail,
  489. int timeOut = Config.TIME_OUT)
  490. {
  491. var data = new
  492. {
  493. touser = openId,
  494. msgtype = "msgmenu",
  495. msgmenu = new
  496. {
  497. head_content = head,
  498. list = menuList,
  499. tail_content = tail
  500. }
  501. };
  502. return ApiHandlerWapper.TryCommonApi(accessToken =>
  503. {
  504. return CommonJsonSend.Send(accessToken, UrlFormat, data, timeOut: timeOut);
  505. }, accessTokenOrAppId);
  506. }
  507. #endregion
  508. #if !NET35 && !NET40
  509. #region 异步方法
  510. /// <summary>
  511. /// 【异步方法】发送文本信息
  512. /// </summary>
  513. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  514. /// <param name="openId"></param>
  515. /// <param name="content"></param>
  516. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  517. /// <param name="kfAccount">客服</param>
  518. /// <returns></returns>
  519. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendTextAsync", true)]
  520. public static async Task<WxJsonResult> SendTextAsync(string accessTokenOrAppId, string openId, string content, int timeOut = Config.TIME_OUT, string kfAccount = "")
  521. {
  522. object data = null;
  523. if (string.IsNullOrEmpty(kfAccount))
  524. {
  525. data = new
  526. {
  527. touser = openId,
  528. msgtype = "text",
  529. text = new
  530. {
  531. content = content
  532. }
  533. };
  534. }
  535. else
  536. {
  537. data = new
  538. {
  539. touser = openId,
  540. msgtype = "text",
  541. text = new
  542. {
  543. content = content
  544. },
  545. customservice = new
  546. {
  547. kf_account = kfAccount
  548. }
  549. };
  550. }
  551. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  552. {
  553. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut);
  554. }, accessTokenOrAppId);
  555. }
  556. /// <summary>
  557. /// 【异步方法】发送图片消息
  558. /// </summary>
  559. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  560. /// <param name="openId"></param>
  561. /// <param name="mediaId"></param>
  562. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  563. /// <param name="kfAccount">客服</param>
  564. /// <returns></returns>
  565. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendImageAsync", true)]
  566. public static async Task<WxJsonResult> SendImageAsync(string accessTokenOrAppId, string openId, string mediaId, int timeOut = Config.TIME_OUT, string kfAccount = "")
  567. {
  568. object data = null;
  569. if (kfAccount.IsNullOrWhiteSpace())
  570. {
  571. data = new
  572. {
  573. touser = openId,
  574. msgtype = "image",
  575. image = new
  576. {
  577. media_id = mediaId
  578. }
  579. };
  580. }
  581. else
  582. {
  583. data = new
  584. {
  585. touser = openId,
  586. msgtype = "image",
  587. image = new
  588. {
  589. media_id = mediaId
  590. },
  591. CustomService = new
  592. {
  593. kf_account = kfAccount
  594. }
  595. };
  596. }
  597. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  598. {
  599. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut);
  600. }, accessTokenOrAppId);
  601. }
  602. /// <summary>
  603. /// 【异步方法】发送语音消息
  604. /// </summary>
  605. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  606. /// <param name="openId"></param>
  607. /// <param name="mediaId"></param>
  608. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  609. /// <param name="kfAccount"></param>
  610. /// <returns></returns>
  611. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendVoiceAsync", true)]
  612. public static async Task<WxJsonResult> SendVoiceAsync(string accessTokenOrAppId, string openId, string mediaId, int timeOut = Config.TIME_OUT, string kfAccount = "")
  613. {
  614. object data = null;
  615. if (kfAccount.IsNullOrWhiteSpace())
  616. {
  617. data = new
  618. {
  619. touser = openId,
  620. msgtype = "voice",
  621. voice = new
  622. {
  623. media_id = mediaId
  624. }
  625. };
  626. }
  627. else
  628. {
  629. data = new
  630. {
  631. touser = openId,
  632. msgtype = "voice",
  633. voice = new
  634. {
  635. media_id = mediaId
  636. },
  637. CustomService = new
  638. {
  639. kf_account = kfAccount
  640. }
  641. };
  642. }
  643. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  644. {
  645. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut);
  646. }, accessTokenOrAppId);
  647. }
  648. /// <summary>
  649. /// 【异步方法】发送视频消息
  650. /// </summary>
  651. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  652. /// <param name="openId"></param>
  653. /// <param name="mediaId"></param>
  654. /// <param name="title"></param>
  655. /// <param name="description"></param>
  656. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  657. /// <param name="kfAccount">客服</param>
  658. /// <param name="thumb_media_id"></param>
  659. /// <returns></returns>
  660. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendVideoAsync", true)]
  661. public static async Task<WxJsonResult> SendVideoAsync(string accessTokenOrAppId, string openId, string mediaId, string title, string description, int timeOut = Config.TIME_OUT, string kfAccount = "", string thumb_media_id = "")
  662. {
  663. object data = null;
  664. if (kfAccount.IsNullOrWhiteSpace())
  665. {
  666. data = new
  667. {
  668. touser = openId,
  669. msgtype = "video",
  670. video = new
  671. {
  672. media_id = mediaId,
  673. thumb_media_id = thumb_media_id,
  674. title = title,
  675. description = description
  676. }
  677. };
  678. }
  679. else
  680. {
  681. data = new
  682. {
  683. touser = openId,
  684. msgtype = "video",
  685. video = new
  686. {
  687. media_id = mediaId,
  688. thumb_media_id = thumb_media_id,
  689. title = title,
  690. description = description
  691. },
  692. CustomService = new
  693. {
  694. kf_account = kfAccount
  695. }
  696. };
  697. }
  698. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  699. {
  700. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut);
  701. }, accessTokenOrAppId);
  702. }
  703. /// <summary>
  704. /// 【异步方法】发送音乐消息
  705. /// </summary>
  706. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  707. /// <param name="openId"></param>
  708. /// <param name="title">音乐标题(非必须)</param>
  709. /// <param name="description">音乐描述(非必须)</param>
  710. /// <param name="musicUrl">音乐链接</param>
  711. /// <param name="hqMusicUrl">高品质音乐链接,wifi环境优先使用该链接播放音乐</param>
  712. /// <param name="thumbMediaId">视频缩略图的媒体ID</param>
  713. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  714. /// <param name="kfAccount">客服</param>
  715. /// <returns></returns>
  716. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendMusicAsync", true)]
  717. public static async Task<WxJsonResult> SendMusicAsync(string accessTokenOrAppId, string openId, string title, string description,
  718. string musicUrl, string hqMusicUrl, string thumbMediaId, int timeOut = Config.TIME_OUT, string kfAccount = "")
  719. {
  720. object data = null;
  721. if (kfAccount.IsNullOrWhiteSpace())
  722. {
  723. data = new
  724. {
  725. touser = openId,
  726. msgtype = "music",
  727. music = new
  728. {
  729. title = title,
  730. description = description,
  731. musicurl = musicUrl,
  732. hqmusicurl = hqMusicUrl,
  733. thumb_media_id = thumbMediaId
  734. }
  735. };
  736. }
  737. else
  738. {
  739. data = new
  740. {
  741. touser = openId,
  742. msgtype = "music",
  743. music = new
  744. {
  745. title = title,
  746. description = description,
  747. musicurl = musicUrl,
  748. hqmusicurl = hqMusicUrl,
  749. thumb_media_id = thumbMediaId
  750. },
  751. CustomService = new
  752. {
  753. kf_account = kfAccount
  754. }
  755. };
  756. }
  757. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  758. {
  759. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut);
  760. }, accessTokenOrAppId);
  761. }
  762. /// <summary>
  763. /// 【异步方法】发送图文消息
  764. /// </summary>
  765. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  766. /// <param name="openId"></param>
  767. /// <param name="articles"></param>
  768. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  769. /// <param name="kfAccount">客服</param>
  770. /// <returns></returns>
  771. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendNewsAsync", true)]
  772. public static async Task<WxJsonResult> SendNewsAsync(string accessTokenOrAppId, string openId, List<Article> articles, int timeOut = Config.TIME_OUT, string kfAccount = "")
  773. {
  774. object data = null;
  775. if (kfAccount.IsNullOrWhiteSpace())
  776. {
  777. data = new
  778. {
  779. touser = openId,
  780. msgtype = "news",
  781. news = new
  782. {
  783. articles = articles.Select(z => new
  784. {
  785. title = z.Title,
  786. description = z.Description,
  787. url = z.Url,
  788. picurl = z.PicUrl //图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80
  789. }).ToList()
  790. }
  791. };
  792. }
  793. else
  794. {
  795. data = new
  796. {
  797. touser = openId,
  798. msgtype = "news",
  799. news = new
  800. {
  801. articles = articles.Select(z => new
  802. {
  803. title = z.Title,
  804. description = z.Description,
  805. url = z.Url,
  806. picurl = z.PicUrl//图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80
  807. }).ToList()
  808. },
  809. CustomService = new
  810. {
  811. kf_account = kfAccount
  812. }
  813. };
  814. }
  815. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  816. {
  817. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut);
  818. }, accessTokenOrAppId);
  819. }
  820. /// <summary>
  821. /// 【异步方法】发送图文消息(点击跳转到图文消息页面)
  822. /// 图文消息条数限制在8条以内,注意,如果图文数超过8,则将会无响应。
  823. /// </summary>
  824. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  825. /// <param name="openId"></param>
  826. /// <param name="mediaId"></param>
  827. /// <param name="timeOut"></param>
  828. /// <param name="kfAccount">客服</param>
  829. /// <returns></returns>
  830. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendMpNewsAsync", true)]
  831. public static async Task<WxJsonResult> SendMpNewsAsync(string accessTokenOrAppId, string openId, string mediaId, int timeOut = Config.TIME_OUT, string kfAccount = "")
  832. {
  833. object data = null;
  834. if (kfAccount.IsNullOrWhiteSpace())
  835. {
  836. data = new
  837. {
  838. touser = openId,
  839. msgtype = "mpnews",
  840. mpnews = new
  841. {
  842. media_id = mediaId
  843. }
  844. };
  845. }
  846. else
  847. {
  848. data = new
  849. {
  850. touser = openId,
  851. msgtype = "mpnews",
  852. mpnews = new
  853. {
  854. media_id = mediaId
  855. },
  856. CustomService = new
  857. {
  858. kf_account = kfAccount
  859. }
  860. };
  861. }
  862. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  863. {
  864. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut);
  865. }, accessTokenOrAppId);
  866. }
  867. /// <summary>
  868. /// 【异步方法】发送卡券
  869. /// </summary>
  870. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  871. /// <param name="openId"></param>
  872. /// <param name="cardId"></param>
  873. /// <param name="cardExt"></param>
  874. /// <param name="timeOut"></param>
  875. /// <returns></returns>
  876. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.SendCardAsync", true)]
  877. public static async Task<WxJsonResult> SendCardAsync(string accessTokenOrAppId, string openId, string cardId, CardExt cardExt, int timeOut = Config.TIME_OUT)
  878. {
  879. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  880. {
  881. var data = new
  882. {
  883. touser = openId,
  884. msgtype = "wxcard",
  885. wxcard = new
  886. {
  887. card_id = cardId,
  888. card_ext = cardExt
  889. }
  890. };
  891. JsonSetting jsonSetting = new JsonSetting()
  892. {
  893. TypesToIgnoreNull = new List<System.Type>() { typeof(CardExt) }
  894. };
  895. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut, jsonSetting: jsonSetting);
  896. }, accessTokenOrAppId);
  897. }
  898. /// <summary>
  899. /// 【异步方法】客服输入状态
  900. /// </summary>
  901. /// <param name="accessTokenOrAppId"></param>
  902. /// <param name="cardId"></param>
  903. /// <param name="typingStatus"></param>
  904. /// <param name="timeOut"></param>
  905. /// <returns></returns>
  906. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "CustomApi.TypingAsync", true)]
  907. public static async Task<WxJsonResult> GetTypingStatusAsync(string accessTokenOrAppId, string cardId, string typingStatus, int timeOut = Config.TIME_OUT)
  908. {
  909. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  910. {
  911. var urlFormat = string.Format(Config.ApiMpHost + "/cgi-bin/message/custom/typing?access_token={0}", accessToken.AsUrlData());
  912. var data = new
  913. {
  914. card_id = cardId,
  915. command = typingStatus
  916. };
  917. return await Weixin.CommonAPIs.CommonJsonSend.SendAsync<WxJsonResult>(null, urlFormat, data, timeOut: timeOut);
  918. }, accessTokenOrAppId);
  919. }
  920. /// <summary>
  921. /// 【异步方法】发送客户菜单消息
  922. /// </summary>
  923. /// <param name="accessTokenOrAppId"></param>
  924. /// <param name="accessTokenOrAppId"></param>
  925. /// <param name="openId">接受人员OPenid</param>
  926. /// <param name="head">标题</param>
  927. /// <param name="menuList">内容</param>
  928. /// <param name="tail">结尾内容</param>
  929. /// <param name="timeOut">超时时间</param>
  930. /// <returns></returns>
  931. public static async Task<WxJsonResult> SendMenuAsync(string accessTokenOrAppId, string openId,
  932. string head, List<SendMenuContent> menuList, string tail,
  933. int timeOut = Config.TIME_OUT)
  934. {
  935. var data = new
  936. {
  937. touser = openId,
  938. msgtype = "msgmenu",
  939. msgmenu = new
  940. {
  941. head_content = head,
  942. list = menuList,
  943. tail_content = tail
  944. }
  945. };
  946. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  947. {
  948. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, UrlFormat, data, timeOut: timeOut);
  949. }, accessTokenOrAppId);
  950. }
  951. #endregion
  952. #endif
  953. /////
  954. ///// 发送卡券 查看card_ext字段详情及签名规则,特别注意客服消息接口投放卡券仅支持非自定义Code码的卡券。
  955. /////
  956. }
  957. }