uni-app + .NET 7 は WeChat アプレット サブスクリプション メッセージ プッシュを実装します

WeChat ミニ プログラムのサブスクリプション メッセージは、クローズド ループ サービスを実現するためのより良いエクスペリエンスを提供するミニ プログラムの重要な機能の 1 つです。サブスクリプション メッセージがよく表示されます. たとえば、注文が正常に行われ、服务通知支払いが成功した後支付成功通知、それらはすべてアプレットのサブスクリプション メッセージに属します.

この記事では、 および の機能のみを実装します一次性订阅これは、会って調査を行う機会がある場合に限られます。长期订阅设备订阅

始める前に、WeChat アプレットのサブスクリプション メッセージの紹介を見てみましょう。

特徴

メッセージ機能は、アプレット機能の重要な部分です.クローズドループサービスとより良いエクスペリエンスを実現するために、開発者にメッセージをサブスクライブする機能を提供します.

  • サブスクリプション メッセージのプッシュ場所: サービス通知
  • 購読メッセージを送信するための条件: ユーザーの自己購読
  • サブスクリプション メッセージ カード ジャンプ機能: クリックして詳細を表示すると、アプレットのページにジャンプします

ここに画像の説明を挿入

メッセージタイプ

1. ニュースの一括購読

ワンタイム購読メッセージは、ユーザーがミニプログラムを使用した後のフォローアップサービスリンクの通知問題を解決するために使用されます。ユーザーが個別にサブスクライブした後、開発者は対応するサービス メッセージを無制限に送信できます。各メッセージは個別にサブスクライブまたはサブスクライブ解除できます。

2. 長期購読ニュース

メッセージへの 1 回限りのサブスクリプションは、ミニ プログラムのほとんどのサービス シナリオのニーズを満たすことができますが、オフライン公共サービスの分野では、フライトの遅延など、1 回限りのサブスクリプションでは満足できないシナリオがあり、複数の通知を行う必要があります。フライトのリアルタイムステータスに従って送信されます。サービスを容易にするために、長期サブスクリプション メッセージを提供します.ユーザーが一度サブスクライブすると、開発者は長期間にわたって複数のメッセージを送信できます.

目前长期性订阅消息仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下公共服务业务。

したがって、通常のアプレットの場合、登録が成功した後、サブスクリプション ニュースのテンプレート選択には 1 回限りのサブスクリプションのオプションしかなく、長期サブスクリプションのオプションはありません。
ここに画像の説明を挿入

3. デバイス サブスクリプション メッセージ

デバイス サブスクリプション メッセージは、特別なタイプのサブスクリプション メッセージであり、長期サブスクリプション メッセージ タイプに属し、使用する前に「デバイス アクセス」を完了する必要があります。

アプレットからのニュースの購読について学習したら、本題に取り掛かりましょう。

基本的なプロセス

予防

以下の記事はまだ非常に長いため、最初に注意事項を示します。ここで問題が解決したことがわかる場合があります。

  • ワンタイム テンプレート ID とパーマネント テンプレート ID を同時に使用することはできません。
  • 下位バージョンの基本ライブラリ 2.4.4 ~ 2.8.3 は、サブスクリプション メッセージ インターフェイスの呼び出しを既にサポートしており、1 回限りの tmplId/永続的な tmplId の受け渡しのみをサポートしています。
  • バージョン 2.8.2 以降、サブスクリプション メッセージ インターフェイスは、ユーザーが支払いコールバックをクリックまたは開始した後にのみ呼び出すことができます。
  • バージョン 2.10.0 以降、アプレットの開発版および試用版では、テンプレート メッセージ formId の使用が禁止されます。
  • 承認呼び出しでは、各 tmplId に対応するテンプレート タイトルが同じ存在することはできません。同じものが存在する場合は、1 つだけが保持されます。
  • バージョン 2.10.0 から、音声メッセージ リマインダーの購読をサポートします。

バージョン ライブラリが 2.8.2 以上の場合、クリック アクションまたは支払いコールバックが開始された後に、サブスクリプション メッセージ インターフェイスを呼び出す必要があります。このクリック動作に特別な要件はありません。たとえば、フォームの場合、送信ボタンをクリックした後、サブスクリプション メッセージ インターフェイスを呼び出すこともできます。支払い後のコールバックをクリックする必要はなく、サブスクリプション メッセージ インターフェイスも呼び出すことができます。

テンプレート ID を取得する

WeChat パブリック プラットフォームのミニ プログラムにログインし、サブスクリプション メッセージ機能の下で、マイ テンプレートを入力し、テンプレートを見つけて、テンプレート ID をコピーします.テンプレートがない場合は、最初にテンプレートを追加してから、テンプレートを取得する必要がありますテンプレートID
ここに画像の説明を挿入

新しいテンプレートを追加するには、选用ボタンをクリックし、公開テンプレート ライブラリで目的のテンプレートを選択して追加します。
ここに画像の説明を挿入

適切なテンプレートがない場合は、カスタム テンプレートを作成できるという記事が多数ありますしかし、本当にカスタム テンプレートを作成したい場合は、どこにも見つからないことがわかります。
カスタム テンプレートを作成する場合は、次の方法で作成できます。
1.选用ボタンをクリックして、公開テンプレート ライブラリに移動します。(公開テンプレート ライブラリのテンプレートは、ミニ プログラムのサービス カテゴリに関連しています)
2. 検索ボックスに、比較的長いキーワードを入力します。
3. テンプレートがまだ一致する場合は、[検索] をクリックし、検索結果がなくなるまでキーワードを再調整します。
4. ページをクリックして、帮忙我们完善模板库カスタム テンプレートを設定します。
ここに画像の説明を挿入
ここに画像の説明を挿入

カスタム テンプレートを作成する場合は、テンプレートの申請プロセス、特に第 1 条をよくお読みください。記事 1 を注意深く読んでおらず、最初のアプリケーションの最初のいくつかのテンプレートを数日間待ったので、それを引き出して強調表示しました。
テンプレートのタイトルは、要求以“通知”或“提醒”结尾ロジスティクスの到着通知、取引のリマインダーなど、特定のサービス シナリオを反映する必要があります。

これを見ると、上記のほとんどはインターネット上の記事と変わらないことがわかりますが、本文はここにあります。

ユニアプリコード

The front-end implementation is to click the submit button, save the form, and send a subscription message after the save is successfully.pages/index/index.vue以下に

<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="服务时间" label-width="160rpx" :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-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="联系电话" label-width="160rpx" :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-width="160rpx" :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 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;">确认提交</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 = 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 つのオブジェクトがあります:およびerrMsg は言うまでもありません。主にこのXXXXXXXXXXとは何か。XXXXXXXXXXXX は承認によって生成され、目視検査によるテンプレート ID です。3. 使用する、入手する4.送信しサーバーに送信すると、サーバーはそれを取得し取得に応じて特定の注文データを取得します。5. テンプレート メッセージを送信します。
uni.requestSubscribeMessagesubscribeMessageReserrMsgXXXXXXXXXXX
uni.logincode
codeorderIdcodeopenIdorderId

予期せぬことが起こらなければ、送信が成功した後、次の承認ボックスがポップアップ表示されます
ここに画像の説明を挿入

サーバーコード

サーバー側の ORM が使用されSqlSugar、WeChat アプレット インターフェイスは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 = 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; }
}

テンプレート メッセージを送信する

1 回限りのサブスクリプション用のテンプレート メッセージを送信すると、渡されたパラメーターがフロント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 = 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";
     //微信小程序要跳转的地址。可以加参数
     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;
}

テンプレート メッセージを構築する場合は、テンプレート メッセージの詳細な内容を次のように想定してIDictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> messageData = new Dictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem>、to を使用して構築します。

ここに画像の説明を挿入

  • 上記のコードの params1 は character_string22 で、params2 は同じように thing7 です。あれは。IDictionary のキーは、.DATAテンプレートの前のコンテンツです。
  • messageRequest.TemplateId、フロント エンドのテンプレート ID と一致する必要があります。
  • messageRequest.MiniProgramStateリダイレクトされた WeChat アプレットのタイプを示します。デフォルトは正式版
    • developer は開発バージョンです。
    • 試用版は試用版です。
    • フォーマルは公式バージョンです。

他に何もなければ、WeChat はサービス通知を受け取ります。カードをクリック後、ミニ番組の注文詳細ページへ!

要約する

1. 実際、WeChat アプレットの購読メッセージと公式アカウントの購読メッセージ テンプレートの申請は比較的簡単です。カテゴリテンプレートや履歴テンプレートで自分に合うテンプレートが見つからない場合は、自分でテンプレートを申請してください。審査が通れば、2~3日で通知が届きます。
需要注意的是,申请模板的时候,最好把各项在本地保留一份。因为一旦提交申请,在公众号或小程序后台,你就找不到了。玩意审核没通过,再申请的时候,前面写的啥内容,已经忘的差不多了!

2. SqlSugar.Net 開発者向けの強力な ORM を提供していただきありがとうございます。本当に便利です。
3. SKIT.FlurlHttpClient.Wechat.Net 開発者に便利なツールを提供していただきありがとうございます。
4.意味をすばやく明確に表現するために、上記のフロントエンドとサーバー側のコードはすべて簡略化されており、直接使用してはなりません!

下の公式アカウントカードをクリックしてフォローしてください!一緒に学び、一緒に進歩しましょう!

おすすめ

転載: blog.csdn.net/sd2208464/article/details/128857921