- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
微信小程序的订阅消息是小程序的重要能力之一,为实现服务的闭环提供更优的体验。订阅消息我们应该经常见到,比如下单成功之后的 服务通知 ,支付成功后的 支付成功通知 ,都属于小程序的订阅消息.
本文只实现 一次性订阅 的功能,至于 长期订阅 与 设备订阅 ,有机会碰到再进行研究.
在开始之前,我们先看看微信小程序订阅消息的介绍:
消息能力是小程序能力中的重要组成,我们为开发者提供了订阅消息能力,以便实现服务的闭环和更优的体验.
1. 一次性订阅消息 。
一次性订阅消息用于解决用户使用小程序后,后续服务环节的通知问题。用户自主订阅后,开发者可不限时间地下发一条对应的服务消息;每条消息可单独订阅或退订.
2. 长期订阅消息 。
一次性订阅消息可满足小程序的大部分服务场景需求,但线下公共服务领域存在一次性订阅无法满足的场景,如航班延误,需根据航班实时动态来多次发送消息提醒。为便于服务,我们提供了长期性订阅消息,用户订阅一次后,开发者可长期下发多条消息.
目前长期性订阅消息仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下公共服务业务.
所以我们普通小程序,在注册成功后,订阅消息的模板选择,只有一次性订阅的选项,没有长期订阅的选项.
3. 设备订阅消息 。
设备订阅消息是一种特殊类型的订阅消息,它属于长期订阅消息类型,且需要完成「设备接入」才能使用.
了解了小程序订阅消息之后,我们开始进入正题! 。
由于后面的文章还很长,注意事项优先发出来,可能看到这里已经解决了你的问题.
特别注意第三条,版本库是2.8.2及以上的时候,订阅消息必须发生点击行为或是发起支付回调后,才可以调起订阅消息的界面。这个点击行为没有特别要求。比如一个表单,点击提交按钮后,也是可以调起订阅消息界面的。支付后的回调不需要点击行为,也可以调起订阅消息界面.
在微信公众平台登录小程序,在订阅消息功能下,进入到我的模板,找到模板,并将模板id复制出来,如果没有模板,需要先添加模板,再获取模板id 。
要添加新模板,点击 选用 按钮,在公共模板库中选择需要的模板,添加就可以了.
有很多文章说, 如果没有合适的模板,可以创建自定义模板 。但如果你真想去创建自定义模板,会发现根本找不到地方。 如果想创建自定义模板,可通过以下方式进行。 1、点击 选用 按钮,来到公共模板库。(公共模板库中的模板,与你小程序的服务类目相关) 2、在搜索框中,输入比较长的关键词。 3、点击搜素,如果还是能匹配出模板来,则重新调整关键词,直到没有任何搜索结果为止。 4、点击页面中的 帮忙我们完善模板库 ,进行自定义模板设置.
创建自定义模板的时候,一定要仔细阅读申请模板的流程,尤其是第1条。我单拉出来重点标注一下,因为没仔细看第1条,第一次申请的几个模板白白等了好几天。 模板标题需体现具体的服务场景, 要求以“通知”或“提醒”结尾 ,如:物流到货通知、交易提醒.
看到这里,会发现以上大部分跟网上的文章没啥区别,别急,正文来了! 。
前端实现的是点击提交按钮,保存表单,保存成功后发送订阅消息,在 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、使用 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 = 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 = 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> 来进行构造, 假设一个模板消息的详细内容是这样的:
.DATA
前面的内容。 messageRequest.TemplateId
,要与前端的模板Id一致。 messageRequest.MiniProgramState
表示跳转微信小程序的类型。默认为正式版
如果不出意外的话,你的微信会收到服务通知。点击卡片后,进入小程序的订单详情页面! 。
1、其实微信小程序的订阅消息和公众号的订阅消息模板还是比较好申请的。如果在类目模板与历史模板中无法找到合适自己的模板,那么自己申请一个模板。审核的话,2-3天就可以收到通知了。 需要注意的是,申请模板的时候,最好把各项在本地保留一份。因为一旦提交申请,在公众号或小程序后台,你就找不到了。玩意审核没通过,再申请的时候,前面写的啥内容,已经忘的差不多了! 。
2、感谢 SqlSugar ,为.Net开发者提供这么强大的ORM。真的是太方便了。 3、感谢 SKIT.FlurlHttpClient.Wechat ,为.Net开发者提供这么便捷的工具。 4、 为了能快速表达清楚意思,以上前端与服务端代码,都是精简过的,万万不可直接使用! 。
作者: gmval 出处: https://www.cnblogs.com/gmval/p/17071237.html 本文版权归作者和博客园共有,写文不易,支持原创,欢迎转载【点赞】,转载请保留此段声明,且在文章页面明显位置给出原文连接,谢谢。 关注个人公众号,定时同步更新优秀资源及技术文章 。
最后此篇关于uni-app+.NET7实现微信小程序订阅消息推送的文章就讲到这里了,如果你想了解更多关于uni-app+.NET7实现微信小程序订阅消息推送的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是 C 语言新手,我编写了这个 C 程序,让用户输入一年中的某一天,作为返回,程序将输出月份以及该月的哪一天。该程序运行良好,但我现在想简化该程序。我知道我需要一个循环,但我不知道如何去做。这是程序
我一直在努力找出我的代码有什么问题。这个想法是创建一个小的画图程序,并有红色、绿色、蓝色和清除按钮。我有我能想到的一切让它工作,但无法弄清楚代码有什么问题。程序打开,然后立即关闭。 import ja
我想安装screen,但是接下来我应该做什么? $ brew search screen imgur-screenshot screen
我有一个在服务器端工作的 UDP 套接字应用程序。为了测试服务器端,我编写了一个简单的 python 客户端程序,它发送消息“hello world how are you”。服务器随后应接收消息,将
我有一个 shell 脚本,它运行一个 Python 程序来预处理一些数据,然后运行一个 R 程序来执行一些长时间运行的任务。我正在学习使用 Docker 并且我一直在运行 FROM r-base:l
在 Linux 中。我有一个 c 程序,它读取一个 2048 字节的文本文件作为输入。我想从 Python 脚本启动 c 程序。我希望 Python 脚本将文本字符串作为参数传递给 c 程序,而不是将
前言 最近开始整理笔记里的库存草稿,本文是 23 年 5 月创建的了(因为中途转移到 onedrive,可能还不止) 网页调起电脑程序是经常用到的场景,比如百度网盘下载,加入 QQ 群之类的 我
对于一个类,我被要求编写一个 VHDL 程序,该程序接受两个整数输入 A 和 B,并用 A+B 替换 A,用 A-B 替换 B。我编写了以下程序和测试平台。它完成了实现和行为语法检查,但它不会模拟。尽
module Algorithm where import System.Random import Data.Maybe import Data.List type Atom = String ty
我想找到两个以上数字的最小公倍数 求给定N个数的最小公倍数的C++程序 最佳答案 int lcm(int a, int b) { return (a/gcd(a,b))*b; } 对于gcd,请查看
这个程序有错误。谁能解决这个问题? Error is :TempRecord already defines a member called 'this' with the same paramete
当我运行下面的程序时,我在 str1 和 str2 中得到了垃圾值。所以 #include #include #include using namespace std; int main() {
这是我的作业: 一对刚出生的兔子(一公一母)被放在田里。兔子在一个月大时可以交配,因此在第二个月的月底,每对兔子都会生出两对新兔子,然后死去。 注:在第0个月,有0对兔子。第 1 个月,有 1 对兔子
我编写了一个程序,通过对字母使用 switch 命令将十进制字符串转换为十六进制,但是如果我使用 char,该程序无法正常工作!没有 switch 我无法处理 9 以上的数字。我希望你能理解我,因为我
我是 C++ 新手(虽然我有一些 C 语言经验)和 MySQL,我正在尝试制作一个从 MySQL 读取数据库的程序,我一直在关注这个 tutorial但当我尝试“构建”解决方案时出现错误。 (我正在使
仍然是一个初学者,只是尝试使用 swift 中的一些基本函数。 有人能告诉我这段代码有什么问题吗? import UIKit var guessInt: Int var randomNum = arc
我正在用 C++11 编写一个函数,它采用 constant1 + constant2 形式的表达式并将它们折叠起来。 constant1 和 constant2 存储在 std::string 中,
我用 C++ 编写了这段代码,使用运算符重载对 2 个矩阵进行加法和乘法运算。当我执行代码时,它会在第 57 行和第 59 行产生错误,非法结构操作(两行都出现相同的错误)。请解释我的错误。提前致谢:
我是 C++ 的初学者,我想编写一个简单的程序来交换字符串中的两个字符。 例如;我们输入这个字符串:“EXAMPLE”,我们给它交换这两个字符:“E”和“A”,输出应该类似于“AXEMPLA”。 我在
我需要以下代码的帮助: 声明 3 个 double 类型变量,每个代表三角形的三个边中的一个。 提示用户为第一面输入一个值,然后 将用户的输入设置为您创建的代表三角形第一条边的变量。 将最后 2 个步
我是一名优秀的程序员,十分优秀!