微信小程式的訂閱訊息是小程式的重要能力之一,為實作服務的倍訓提供更優的體驗,訂閱訊息我們應該經常見到,比如下單成功之后的服務通知,支付成功后的支付成功通知,都屬于小程式的訂閱訊息,
本文只實作一次性訂閱的功能,至于長期訂閱與設備訂閱,有機會碰到再進行研究,
- 功能介紹
- 訊息型別
- 基本流程
- 注意事項
- 獲取模板ID
- uni-app代碼
- 服務端代碼
- 生成訂單
- 發送模板訊息
- 總結
在開始之前,我們先看看微信小程式訂閱訊息的介紹:
功能介紹
訊息能力是小程式能力中的重要組成,我們為開發者提供了訂閱訊息能力,以便實作服務的倍訓和更優的體驗,
- 訂閱訊息推送位置:服務通知
- 訂閱訊息下發條件:用戶自主訂閱
- 訂閱訊息卡片跳轉能力:點擊查看詳情可跳轉至該小程式的頁面

訊息型別
1. 一次性訂閱訊息
一次性訂閱訊息用于解決用戶使用小程式后,后續服務環節的通知問題,用戶自主訂閱后,開發者可不限時間地下發一條對應的服務訊息;每條訊息可單獨訂閱或退訂,
2. 長期訂閱訊息
一次性訂閱訊息可滿足小程式的大部分服務場景需求,但線下公共服務領域存在一次性訂閱無法滿足的場景,如航班延誤,需根據航班實時動態來多次發送訊息提醒,為便于服務,我們提供了長期性訂閱訊息,用戶訂閱一次后,開發者可長期下發多條訊息,
目前長期性訂閱訊息僅向政務民生、醫療、交通、金融、教育等線下公共服務開放,后期將逐步支持到其他線下公共服務業務,
所以我們普通小程式,在注冊成功后,訂閱訊息的模板選擇,只有一次性訂閱的選項,沒有長期訂閱的選項,

3. 設備訂閱訊息
設備訂閱訊息是一種特殊型別的訂閱訊息,它屬于長期訂閱訊息型別,且需要完成「設備接入」才能使用,
了解了小程式訂閱訊息之后,我們開始進入正題!
基本流程
注意事項
由于后面的文章還很長,注意事項優先發出來,可能看到這里已經解決了你的問題,
- 一次性模板 id 和永久模板 id 不可同時使用,
- 低版本基礎庫2.4.4~2.8.3 已支持訂閱訊息介面呼叫,僅支持傳入一個一次性 tmplId / 永久 tmplId,
- 2.8.2 版本開始,用戶發生點擊行為或者發起支付回呼后,才可以調起訂閱訊息界面
- 2.10.0 版本開始,開發版和體驗版小程式將禁止使用模板訊息 formId,
- 一次授權呼叫里,每個 tmplId 對應的模板標題不能存在相同的,若出現相同的,只保留一個,
- 2.10.0 版本開始,支持訂閱語音訊息提醒
特別注意第三條,版本庫是2.8.2及以上的時候,訂閱訊息必須發生點擊行為或是發起支付回呼后,才可以調起訂閱訊息的界面,這個點擊行為沒有特別要求,比如一個表單,點擊提交按鈕后,也是可以調起訂閱訊息界面的,支付后的回呼不需要點擊行為,也可以調起訂閱訊息界面,
獲取模板ID
在微信公眾平臺登錄小程式,在訂閱訊息功能下,進入到我的模板,找到模板,并將模板id復制出來,如果沒有模板,需要先添加模板,再獲取模板id

要添加新模板,點擊選用按鈕,在公共模板庫中選擇需要的模板,添加就可以了,

有很多文章說,如果沒有合適的模板,可以創建自定義模板,但如果你真想去創建自定義模板,會發現根本找不到地方,
如果想創建自定義模板,可通過以下方式進行,
1、點擊選用按鈕,來到公共模板庫,(公共模板庫中的模板,與你小程式的服務類目相關)
2、在搜索框中,輸入比較長的關鍵詞,
3、點擊搜素,如果還是能匹配出模板來,則重新調整關鍵詞,直到沒有任何搜索結果為止,
4、點擊頁面中的幫忙我們完善模板庫,進行自定義模板設定,


創建自定義模板的時候,一定要仔細閱讀申請模板的流程,尤其是第1條,我單拉出來重點標注一下,因為沒仔細看第1條,第一次申請的幾個模板白白等了好幾天,
模板標題需體現具體的服務場景,要求以“通知”或“提醒”結尾,如:物流到貨通知、交易提醒,
看到這里,會發現以上大部分跟網上的文章沒啥區別,別急,正文來了!
uni-app代碼
前端實作的是點擊提交按鈕,保存表單,保存成功后發送訂閱訊息,在pages/index/index.vue下撰寫如下代碼:
<template>
<view>
<view >
<publishStep :list="setpList" :current="0" mode="number" active-color="#eb3572"></publishStep>
</view>
<view >
<u-form :model="form" ref="uForm" :rules="rules" :error-type="errorType">
<u-form-item label="姓名" label- :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="服務時間" label- :border-bottom="true" :label-style="{'font-size':'28rpx'}"
right-icon="arrow-right" prop="serviceTime">
<u-input v-model="form.serviceTime" placeholder="請選擇服務時間" :disabled="true" input-align="right" @click="timeShow=true" />
</u-form-item>
<u-form-item label="服務地址" label- :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="聯系電話" label- :border-bottom="true" :label-style="{'font-size':'28rpx'}"
prop="lxtel">
<u-input v-model="form.lxtel" type="number" placeholder="請輸入聯系電話" input-align="right" :clearable="false" />
</u-form-item>
<u-form-item label="需求描述" label- :border-bottom="true" :label-style="{'font-size':'28rpx'}"
prop="remarks">
<u-input v-model="form.remarks" type="text" placeholder="請輸入您的需求" input-align="right" :clearable="false" />
</u-form-item>
</u-form>
</view>
<view style="height: 160rpx;"></view>
<view >
<view >
<u-button type="error" @click="submitForm" :loading="submit_loading" style="height: 100rpx; font-weight: bold; font-size: 36rpx;">確認提交</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: "請填寫您的姓名",
trigger: 'change'
}],
serviceTime: [{
required: true,
message: "請選擇服務時間",
trigger: 'change'
}],
lxtel: [{
required: true,
message: "請輸入聯系電話",
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 = https://www.cnblogs.com/gmval/archive/2023/02/04/res.data;
uni.showToast({
title:'提交成功',
icon: 'success'
})
// #ifdef MP-WEIXIN
uni.requestSubscribeMessage({
tmplIds:['XXXXXXXXXXX'], //這里填寫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、提交表單,服務端回傳訂單號(orderId)
2、使用uni.requestSubscribeMessage,調起授權框,當點擊同意后,進入第三步,調起授權后,如果用戶同意,回呼函式的引數subscribeMessageRes有兩個物件:errMsg和XXXXXXXXXXX,errMsg不必多說,主要是這個XXXXXXXXXXX是什么,XXXXXXXXXXX是授權生成的,目測來看就是模板Id,
3、使用uni.login,獲取code,
4、將code與orderId發送到服務器,服務器通過code獲取到openId,再根據orderId獲取到具體訂單資料,
5、發送模板訊息,
如果不出意外的話,提交成功后,彈出如下授權框

服務端代碼
服務端ORM使用SqlSugar,微信小程式介面使用SKIT.FlurlHttpClient.Wechat庫,
生成訂單
提交訂單,這里只做演示,具體的代碼自己實作下就可以了!
[HttpPost]
public async Task<AjaxResult> SubmitOrder(order model)
{
//生成訂單號
model.order_no = DateTime.Now.ToString("yyyyMMddHHssfffff");
model.addtime = DateTime.Now;
//ExecuteReturnIdentity方法會回傳自增id
var id = await db.Insertable(model).ExecuteReturnIdentity();
return new AjaxResult(){
success=true,
data = https://www.cnblogs.com/gmval/archive/2023/02/04/id
};
}
AjaxResult.cs
public class AjaxResult
{
/// <summary>
/// 是否成功
/// </summary>
public bool success { get; set; } = true;
/// <summary>
/// 錯誤代碼
/// </summary>
public int code { get; set; } = 0;
/// <summary>
/// 回傳訊息
/// </summary>
public string message { get; set; }
/// <summary>
/// 回傳資料
/// </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>
/// 訂單編號
/// </summary>
public string order_no { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string realName { get; set; }
/// <summary>
/// 時間
/// </summary>
public DateTime serviceTime { get; set; }
/// <summary>
/// 地址
/// </summary>
public string serviceAddress { get; set; }
/// <summary>
/// 聯系電話
/// </summary>
public string lxtel { get; set; }
/// <summary>
/// 備注
/// </summary>
public string remarks { get; set; }
/// <summary>
/// 創建時間
/// </summary>
public DateTime addtime { get; set; }
}
發送模板訊息
發送一次性訂閱的模板訊息,傳的引數為前端獲取的code與orderId,根據訂單編號獲取訂單資訊,以便在訂閱訊息中,設定小程式資訊以及打開路徑,code用于獲取用戶的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 = "引數錯誤";
return result;
}
var order_model = await db.Queryable<order>().InSingleAsync(orderId);
if(order_model is null)
{
result.success = false;
result.message = "引數錯誤";
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;
//發送模板訊息
var messageRequest = new CgibinMessageSubscribeSendRequest();
IDictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> messageData = https://www.cnblogs.com/gmval/archive/2023/02/04/new Dictionary
{
{"params1",
new CgibinMessageSubscribeSendRequest.Types.DataItem() {Value=https://www.cnblogs.com/gmval/archive/2023/02/04/order_model.order_no}
},
{"params1",
new CgibinMessageSubscribeSendRequest.Types.DataItem(){Value=https://www.cnblogs.com/gmval/archive/2023/02/04/order_model.userNmae}
},
{"params3",
new CgibinMessageSubscribeSendRequest.Types.DataItem(){Value=https://www.cnblogs.com/gmval/archive/2023/02/04/order_model.serviceTime}
},
{"params4",
new CgibinMessageSubscribeSendRequest.Types.DataItem(){Value=https://www.cnblogs.com/gmval/archive/2023/02/04/order_model.serviceAddress}
},
{"params5",
new CgibinMessageSubscribeSendRequest.Types.DataItem(){Value=https://www.cnblogs.com/gmval/archive/2023/02/04/order_model.addtime.ToString("yyyy-MM-dd HH:ss")}
}
};
messageRequest.AccessToken = token;
messageRequest.ToUserOpenId = openId;
messageRequest.TemplateId = "XXXXXXXXXXX";
messageRequest.MiniProgramState = "developer";
//微信小程式要跳轉的地址,可以加引數
messageRequest.MiniProgramPagePath = "/pages/order/order_details?id=" + order_model.id;
messageRequest.Data = https://www.cnblogs.com/gmval/archive/2023/02/04/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;
}
構造模板訊息的時候,使用IDictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> messageData = https://www.cnblogs.com/gmval/archive/2023/02/04/new Dictionary來進行構造,
假設一個模板訊息的詳細內容是這樣的:

- 那么上面代碼中的params1 就是character_string22,同理params2就是thing7,也就是說,IDictionary的key就是模板中
.DATA前面的內容, messageRequest.TemplateId,要與前端的模板Id一致,messageRequest.MiniProgramState表示跳轉微信小程式的型別,默認為正式版- developer為開發版;
- trial為體驗版;
- formal為正式版;
如果不出意外的話,你的微信會收到服務通知,點擊卡片后,進入小程式的訂單詳情頁面!
總結
1、其實微信小程式的訂閱訊息和公眾號的訂閱訊息模板還是比較好申請的,如果在類目模板與歷史模板中無法找到合適自己的模板,那么自己申請一個模板,審核的話,2-3天就可以收到通知了,
需要注意的是,申請模板的時候,最好把各項在本地保留一份,因為一旦提交申請,在公眾號或小程式后臺,你就找不到了,玩意審核沒通過,再申請的時候,前面寫的啥內容,已經忘的差不多了!
2、感謝SqlSugar,為.Net開發者提供這么強大的ORM,真的是太方便了,
3、感謝SKIT.FlurlHttpClient.Wechat,為.Net開發者提供這么便捷的工具,
4、為了能快速表達清楚意思,以上前端與服務端代碼,都是精簡過的,萬萬不可直接使用!
作者:gmval
出處:https://www.cnblogs.com/gmval/p/17071237.html
本文著作權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段宣告,且在文章頁面明顯位置給出原文連接,謝謝,
關注個人公眾號,定時同步更新優秀資源及技術文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/542986.html
標籤:.NET技术
