uni-app結(jié)合.NET?7實(shí)現(xiàn)微信小程序訂閱消息推送
微信小程序的訂閱消息是小程序的重要能力之一,為實(shí)現(xiàn)服務(wù)的閉環(huán)提供更優(yōu)的體驗(yàn)。訂閱消息我們應(yīng)該經(jīng)常見(jiàn)到,比如下單成功之后的服務(wù)通知
,支付成功后的支付成功通知
,都屬于小程序的訂閱消息。
本文只實(shí)現(xiàn)一次性訂閱
的功能,至于長(zhǎng)期訂閱
與設(shè)備訂閱
,有機(jī)會(huì)碰到再進(jìn)行研究。
在開(kāi)始之前,我們先看看微信小程序訂閱消息的介紹:
功能介紹
消息能力是小程序能力中的重要組成,我們?yōu)殚_(kāi)發(fā)者提供了訂閱消息能力,以便實(shí)現(xiàn)服務(wù)的閉環(huán)和更優(yōu)的體驗(yàn)。
- 訂閱消息推送位置:服務(wù)通知
- 訂閱消息下發(fā)條件:用戶(hù)自主訂閱
- 訂閱消息卡片跳轉(zhuǎn)能力:點(diǎn)擊查看詳情可跳轉(zhuǎn)至該小程序的頁(yè)面
消息類(lèi)型
1. 一次性訂閱消息
一次性訂閱消息用于解決用戶(hù)使用小程序后,后續(xù)服務(wù)環(huán)節(jié)的通知問(wèn)題。用戶(hù)自主訂閱后,開(kāi)發(fā)者可不限時(shí)間地下發(fā)一條對(duì)應(yīng)的服務(wù)消息;每條消息可單獨(dú)訂閱或退訂。
2. 長(zhǎng)期訂閱消息
一次性訂閱消息可滿(mǎn)足小程序的大部分服務(wù)場(chǎng)景需求,但線(xiàn)下公共服務(wù)領(lǐng)域存在一次性訂閱無(wú)法滿(mǎn)足的場(chǎng)景,如航班延誤,需根據(jù)航班實(shí)時(shí)動(dòng)態(tài)來(lái)多次發(fā)送消息提醒。為便于服務(wù),我們提供了長(zhǎng)期性訂閱消息,用戶(hù)訂閱一次后,開(kāi)發(fā)者可長(zhǎng)期下發(fā)多條消息。
目前長(zhǎng)期性訂閱消息僅向政務(wù)民生、醫(yī)療、交通、金融、教育等線(xiàn)下公共服務(wù)開(kāi)放,后期將逐步支持到其他線(xiàn)下公共服務(wù)業(yè)務(wù)。
所以我們普通小程序,在注冊(cè)成功后,訂閱消息的模板選擇,只有一次性訂閱的選項(xiàng),沒(méi)有長(zhǎng)期訂閱的選項(xiàng)。
3. 設(shè)備訂閱消息
設(shè)備訂閱消息是一種特殊類(lèi)型的訂閱消息,它屬于長(zhǎng)期訂閱消息類(lèi)型,且需要完成「設(shè)備接入」才能使用。
了解了小程序訂閱消息之后,我們開(kāi)始進(jìn)入正題!
基本流程
注意事項(xiàng)
由于后面的文章還很長(zhǎng),注意事項(xiàng)優(yōu)先發(fā)出來(lái),可能看到這里已經(jīng)解決了你的問(wèn)題。
- 一次性模板 id 和永久模板 id 不可同時(shí)使用。
- 低版本基礎(chǔ)庫(kù)2.4.4~2.8.3 已支持訂閱消息接口調(diào)用,僅支持傳入一個(gè)一次性 tmplId / 永久 tmplId。
- 2.8.2 版本開(kāi)始,用戶(hù)發(fā)生點(diǎn)擊行為或者發(fā)起支付回調(diào)后,才可以調(diào)起訂閱消息界面
- 2.10.0 版本開(kāi)始,開(kāi)發(fā)版和體驗(yàn)版小程序?qū)⒔故褂媚0逑?formId。
- 一次授權(quán)調(diào)用里,每個(gè) tmplId 對(duì)應(yīng)的模板標(biāo)題不能存在相同的,若出現(xiàn)相同的,只保留一個(gè)。
- 2.10.0 版本開(kāi)始,支持訂閱語(yǔ)音消息提醒
特別注意第三條,版本庫(kù)是2.8.2及以上的時(shí)候,訂閱消息必須發(fā)生點(diǎn)擊行為或是發(fā)起支付回調(diào)后,才可以調(diào)起訂閱消息的界面。這個(gè)點(diǎn)擊行為沒(méi)有特別要求。比如一個(gè)表單,點(diǎn)擊提交按鈕后,也是可以調(diào)起訂閱消息界面的。支付后的回調(diào)不需要點(diǎn)擊行為,也可以調(diào)起訂閱消息界面。
獲取模板ID
在微信公眾平臺(tái)登錄小程序,在訂閱消息功能下,進(jìn)入到我的模板,找到模板,并將模板id復(fù)制出來(lái),如果沒(méi)有模板,需要先添加模板,再獲取模板id
要添加新模板,點(diǎn)擊選用
按鈕,在公共模板庫(kù)中選擇需要的模板,添加就可以了。
有很多文章說(shuō),如果沒(méi)有合適的模板,可以創(chuàng)建自定義模板。但如果你真想去創(chuàng)建自定義模板,會(huì)發(fā)現(xiàn)根本找不到地方。
如果想創(chuàng)建自定義模板,可通過(guò)以下方式進(jìn)行。
1、點(diǎn)擊選用
按鈕,來(lái)到公共模板庫(kù)。(公共模板庫(kù)中的模板,與你小程序的服務(wù)類(lèi)目相關(guān))
2、在搜索框中,輸入比較長(zhǎng)的關(guān)鍵詞。
3、點(diǎn)擊搜素,如果還是能匹配出模板來(lái),則重新調(diào)整關(guān)鍵詞,直到?jīng)]有任何搜索結(jié)果為止。
4、點(diǎn)擊頁(yè)面中的幫忙我們完善模板庫(kù)
,進(jìn)行自定義模板設(shè)置。
創(chuàng)建自定義模板的時(shí)候,一定要仔細(xì)閱讀申請(qǐng)模板的流程,尤其是第1條。我單拉出來(lái)重點(diǎn)標(biāo)注一下,因?yàn)闆](méi)仔細(xì)看第1條,第一次申請(qǐng)的幾個(gè)模板白白等了好幾天。
模板標(biāo)題需體現(xiàn)具體的服務(wù)場(chǎng)景,要求以“通知”或“提醒”結(jié)尾
,如:物流到貨通知、交易提醒。
看到這里,會(huì)發(fā)現(xiàn)以上大部分跟網(wǎng)上的文章沒(méi)啥區(qū)別,別急,正文來(lái)了!
uni-app代碼
前端實(shí)現(xiàn)的是點(diǎn)擊提交按鈕,保存表單,保存成功后發(fā)送訂閱消息,在pages/index/index.vue
下編寫(xiě)如下代碼:
<template> <view> <view class="setp"> <publishStep :list="setpList" :current="0" mode="number" active-color="#eb3572"></publishStep> </view> <view class="container"> <u-form :model="form" ref="uForm" :rules="rules" :error-type="errorType"> <u-form-item label="姓名" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}" prop="realName"> <u-input v-model="form.realName" placeholder="" input-align="right" /> </u-form-item> <u-form-item label="服務(wù)時(shí)間" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}" right-icon="arrow-right" prop="serviceTime"> <u-input v-model="form.serviceTime" placeholder="請(qǐng)選擇服務(wù)時(shí)間" :disabled="true" input-align="right" @click="timeShow=true" /> </u-form-item> <u-form-item label="服務(wù)地址" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}" prop="serviceAddress"> <u-input v-model="form.serviceAddress" placeholder="" input-align="right" @click="selectAddress" /> </u-form-item> <u-form-item label="聯(lián)系電話(huà)" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}" prop="lxtel"> <u-input v-model="form.lxtel" type="number" placeholder="請(qǐng)輸入聯(lián)系電話(huà)" input-align="right" :clearable="false" /> </u-form-item> <u-form-item label="需求描述" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}" prop="remarks"> <u-input v-model="form.remarks" type="text" placeholder="請(qǐng)輸入您的需求" input-align="right" :clearable="false" /> </u-form-item> </u-form> </view> <view style="height: 160rpx;"></view> <view class="bottom_nav"> <view class="buttom_box padding-horizontal-20 padding-vertical-10"> <u-button type="error" @click="submitForm" :loading="submit_loading" style="height: 100rpx; font-weight: bold; font-size: 36rpx;">確認(rèn)提交</u-button> </view> </view> <u-picker mode="time" v-model="timeShow" :params="timeParams" @confirm="timeConfirm"></u-picker> </view> </template> <script> export default { data() { return { form:{ realName:"", serviceTime:'', serviceAddress:"", lxtel:"", remarks:"" }, rules:{ realName: [{ required: true, message: "請(qǐng)?zhí)顚?xiě)您的姓名", trigger: 'change' }], serviceTime: [{ required: true, message: "請(qǐng)選擇服務(wù)時(shí)間", trigger: 'change' }], lxtel: [{ required: true, message: "請(qǐng)輸入聯(lián)系電話(huà)", trigger: 'change' }], }, errorType: ['toast'], timeShow:false, timeParams:{ year: true, month: true, day: true, hour: false, minute: false, second: false }, submit_loading:false, } }, onReady() { this.$refs.uForm.setRules(this.rules); }, onLoad(params) { let that = this; }, methods: { timeConfirm(e){ let that = this; that.form.serviceTime = e.year +"-"+e.month+"-"+e.day }, gotoOrder(){ uni.redirectTo({ url:"/pages/order/order" }) }, submitForm(){ let that = this; this.$refs.uForm.validate(valid=>{ if (valid){ that.$u.api.submit_order(that.form).then(res => { if (res.success) { let data = res.data; uni.showToast({ title: '提交成功', icon: 'success' }) // #ifdef MP-WEIXIN uni.requestSubscribeMessage({ tmplIds:['XXXXXXXXXXX'], //這里填寫(xiě)tempid success:function(subscribeMessageRes){ if(subscribeMessageRes.errMsg=="requestSubscribeMessage:ok"){ if(subscribeMessageRes.XXXXXXXXXXX=="accept"){ uni.login({ provider: 'weixin', success:function(loginRes){ if(loginRes.errMsg=="login:ok"){ const code = loginRes.code; that.$u.api.sendSubscribeMessage({ "code":code, "orderId":data.orderId }).then(res=>{ that.gotoOrder() }) }else{ that.gotoOrder() } }, fail() { that.gotoOrder() } }) }else{ that.gotoOrder() } }else{ that.gotoOrder() } }, fail:function(){ that.gotoOrder() } }) // #endif } else { uni.$u.toast(res.message); } }); } }) } } } </script> <style> .setp{ padding: 40rpx 0;} .bottom_nav { position: fixed; width: 100%; height: 100rpx; left: 0; bottom: 0; z-index: 9999; background: #FFFFFF; border-top: 1rpx #f3f3f3 solid; } </style>
這里的流程分為3步:
1、提交表單,服務(wù)端返回訂單號(hào)(orderId)
2、使用uni.requestSubscribeMessage
,調(diào)起授權(quán)框,當(dāng)點(diǎn)擊同意后,進(jìn)入第三步。調(diào)起授權(quán)后,如果用戶(hù)同意,回調(diào)函數(shù)的參數(shù)subscribeMessageRes
有兩個(gè)對(duì)象:errMsg
和XXXXXXXXXXX
,errMsg不必多說(shuō)。主要是這個(gè)XXXXXXXXXXX是什么。XXXXXXXXXXX是授權(quán)生成的,目測(cè)來(lái)看就是模板Id。
3、使用uni.login
,獲取code
。
4、將code
與orderId
發(fā)送到服務(wù)器,服務(wù)器通過(guò)code
獲取到openId
,再根據(jù)orderId
獲取到具體訂單數(shù)據(jù)。
5、發(fā)送模板消息。
如果不出意外的話(huà),提交成功后,彈出如下授權(quán)框
服務(wù)端代碼
服務(wù)端ORM使用SqlSugar
,微信小程序接口使用SKIT.FlurlHttpClient.Wechat
庫(kù)。
生成訂單
提交訂單,這里只做演示,具體的代碼自己實(shí)現(xiàn)下就可以了!
[HttpPost] public async Task<AjaxResult> SubmitOrder(order model) { //生成訂單號(hào) model.order_no = DateTime.Now.ToString("yyyyMMddHHssfffff"); model.addtime = DateTime.Now; //ExecuteReturnIdentity方法會(huì)返回自增id var id = await db.Insertable(model).ExecuteReturnIdentity(); return new AjaxResult(){ success=true, data = id }; }
AjaxResult.cs
public class AjaxResult { /// <summary> /// 是否成功 /// </summary> public bool success { get; set; } = true; /// <summary> /// 錯(cuò)誤代碼 /// </summary> public int code { get; set; } = 0; /// <summary> /// 返回消息 /// </summary> public string message { get; set; } /// <summary> /// 返回?cái)?shù)據(jù) /// </summary> public object data{ get; set;} }
order.cs
[SugarTable("order")] public class order { /// <summary> /// 主鍵,自增Id /// </summary> [SugarColumn(IsPrimaryKey = true)] public int id { get; set; } /// <summary> /// 訂單編號(hào) /// </summary> public string order_no { get; set; } /// <summary> /// 姓名 /// </summary> public string realName { get; set; } /// <summary> /// 時(shí)間 /// </summary> public DateTime serviceTime { get; set; } /// <summary> /// 地址 /// </summary> public string serviceAddress { get; set; } /// <summary> /// 聯(lián)系電話(huà) /// </summary> public string lxtel { get; set; } /// <summary> /// 備注 /// </summary> public string remarks { get; set; } /// <summary> /// 創(chuàng)建時(shí)間 /// </summary> public DateTime addtime { get; set; } }
發(fā)送模板消息
發(fā)送一次性訂閱的模板消息,傳的參數(shù)為前端獲取的code
與orderId
。根據(jù)訂單編號(hào)獲取訂單信息,以便在訂閱消息中,設(shè)置小程序信息以及打開(kāi)路徑。code
用于獲取用戶(hù)的openId
。
[HttpPost] public async Task<AjaxResult> SendSubscribeMessage(string code,string orderId) { AjaxResult result = new AjaxResult(); if (string.IsNullOrEmpty(code) || string.IsNullOrEmpty(orderId)) { result.success = false; result.message = "參數(shù)錯(cuò)誤"; return result; } var order_model = await db.Queryable<order>().InSingleAsync(orderId); if(order_model is null) { result.success = false; result.message = "參數(shù)錯(cuò)誤"; return result; } //初始化WechatApiClient var options = new WechatApiClientOptions() { AppId = "appId", AppSecret = "appSecret " }; var client = new WechatApiClient(options); //獲取openId var request = new SnsJsCode2SessionRequest(); request.JsCode = code; var response = await client.ExecuteSnsJsCode2SessionAsync(request); string openId = response.OpenId; //獲取token var tokenRequest = new CgibinTokenRequest(); var tokenResponse = await client.ExecuteCgibinTokenAsync(tokenRequest); var token = tokenResponse.AccessToken; //發(fā)送模板消息 var messageRequest = new CgibinMessageSubscribeSendRequest(); IDictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> messageData = new Dictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> { { "params1", new CgibinMessageSubscribeSendRequest.Types.DataItem() {Value=order_model.order_no} }, { "params1", new CgibinMessageSubscribeSendRequest.Types.DataItem(){Value=order_model.userNmae} }, { "params3", new CgibinMessageSubscribeSendRequest.Types.DataItem(){Value=order_model.serviceTime} }, { "params4", new CgibinMessageSubscribeSendRequest.Types.DataItem(){Value=order_model.serviceAddress} }, { "params5", new CgibinMessageSubscribeSendRequest.Types.DataItem(){Value=order_model.addtime.ToString("yyyy-MM-dd HH:ss")} } }; messageRequest.AccessToken = token; messageRequest.ToUserOpenId = openId; messageRequest.TemplateId = "XXXXXXXXXXX"; messageRequest.MiniProgramState = "developer"; //微信小程序要跳轉(zhuǎn)的地址??梢约訁?shù) messageRequest.MiniProgramPagePath = "/pages/order/order_details?id=" + order_model.id; messageRequest.Data = messageData; var messageResponse = await client.ExecuteCgibinMessageSubscribeSendAsync(messageRequest); if(messageResponse.ErrorCode==0) { result.success=true; result.message = "ok"; return result; } result.success = false; result.message = "error"; return result; }
構(gòu)造模板消息的時(shí)候,使用IDictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> messageData = new Dictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem>
來(lái)進(jìn)行構(gòu)造,
假設(shè)一個(gè)模板消息的詳細(xì)內(nèi)容是這樣的:
- 那么上面代碼中的params1 就是character_string22,同理params2就是thing7。也就是說(shuō)。IDictionary的key就是模板中
.DATA
前面的內(nèi)容。 messageRequest.TemplateId
,要與前端的模板Id一致。messageRequest.MiniProgramState
表示跳轉(zhuǎn)微信小程序的類(lèi)型。默認(rèn)為正式版- developer為開(kāi)發(fā)版;
- trial為體驗(yàn)版;
- formal為正式版;
如果不出意外的話(huà),你的微信會(huì)收到服務(wù)通知。點(diǎn)擊卡片后,進(jìn)入小程序的訂單詳情頁(yè)面!
總結(jié)
1、其實(shí)微信小程序的訂閱消息和公眾號(hào)的訂閱消息模板還是比較好申請(qǐng)的。如果在類(lèi)目模板與歷史模板中無(wú)法找到合適自己的模板,那么自己申請(qǐng)一個(gè)模板。審核的話(huà),2-3天就可以收到通知了。需要注意的是,申請(qǐng)模板的時(shí)候,最好把各項(xiàng)在本地保留一份。因?yàn)橐坏┨峤簧暾?qǐng),在公眾號(hào)或小程序后臺(tái),你就找不到了。玩意審核沒(méi)通過(guò),再申請(qǐng)的時(shí)候,前面寫(xiě)的啥內(nèi)容,已經(jīng)忘的差不多了!
2、感謝SqlSugar
,為.Net開(kāi)發(fā)者提供這么強(qiáng)大的ORM。真的是太方便了。
3、感謝SKIT.FlurlHttpClient.Wechat
,為.Net開(kāi)發(fā)者提供這么便捷的工具。
4、為了能快速表達(dá)清楚意思,以上前端與服務(wù)端代碼,都是精簡(jiǎn)過(guò)的,萬(wàn)萬(wàn)不可直接使用!
到此這篇關(guān)于uni-app結(jié)合.NET 7實(shí)現(xiàn)微信小程序訂閱消息推送的文章就介紹到這了,更多相關(guān)uni-app .NET 7小程序消息推送內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Asp.Net FckEditor在web.config中配置的具體實(shí)例
Asp.Net FckEditor在web.config中配置的具體實(shí)例,需要的朋友可以參考一下2013-06-06在 .NET Framework 2.0 中未處理的異常導(dǎo)致基于 ASP.NET 的應(yīng)用程序意外退出
如果在 Microsoft .NET Framework 2.0 上構(gòu)建的基于 Microsoft ASP.NET 的應(yīng)用程序中引發(fā)未處理的異常,該應(yīng)用程序?qū)?huì)意外退出。如果出現(xiàn)這個(gè)問(wèn)題,不會(huì)在應(yīng)用程序日志中記錄了解此問(wèn)題所必需的異常信息。2009-11-11MVC4制作網(wǎng)站教程第三章 刪除用戶(hù)組操作3.4
這篇文章主要為大家詳細(xì)介紹了MVC4制作網(wǎng)站教程,刪除用戶(hù)組功能的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08IIS上部署你的ASP.NET?Core?Web?Api項(xiàng)目及Swagger(圖文)
本篇經(jīng)驗(yàn)將和大家介紹如何在IIS上部署ASP.NET?Core項(xiàng)目,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,希望為初學(xué).NET?CORE的童靴入門(mén)有所幫助2023-09-09Asp.net MVC使用swupload實(shí)現(xiàn)多圖片上傳功能
這篇文章主要為大家詳細(xì)介紹了Asp.net MVC使用swupload實(shí)現(xiàn)多圖片上傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07ASP.NET數(shù)據(jù)庫(kù)編程之Access連接失敗
ASP.NET數(shù)據(jù)庫(kù)編程之Access連接失敗...2006-09-09asp.net顯示相同數(shù)字相乘的結(jié)果,直到數(shù)值大于150為止
老師布置Insus.NET做的第二道題,題目如標(biāo)題。感興趣的網(wǎng)友也可以練習(xí)練習(xí)?,F(xiàn)在Insus.NET的作答如下,但老師還沒(méi)有看,因此答案是否正確或是最好的,還不能確定,只是供參考2012-05-05