- 开发者工具什么时候可以支持M1芯片的MAC?
如题
2020-11-11 - 小程序云开发模糊查询,实现数据库多字段的模糊搜索
最近做小程序云开发时,用到了一个数据库的模糊搜索功能,并且是要求多字段的模糊搜索。 网上也有一大堆资源,但是都是单个字段的搜索。如下图 [图片] 上图只可以实现time字段的模糊搜索。但是我们如果相对数据表里的多个字段做模糊查询呢?该怎么办呢。 多字段模糊搜索 一,如我们的数据表里有以下数据,我们想同时模糊查询name和address字段 [图片] [图片] 如我们搜索“周杰”可以看到我们查询到下面两条数据。 [图片] 二,如我们搜索“编程”,可以搜索到下面数据 [图片] 可以看到我们搜索到的两条数据,一个是name字段为 编程小石头, 一个是address字段里包含“编程“ 字样。 下面把代码贴给大家 [代码] let key = "编程小石头"; console.log("查询的内容", key) const db = wx.cloud.database(); const _ = db.command db.collection('qcl').where(_.or([{ name: db.RegExp({ regexp: '.*' + key, options: 'i', }) }, { address: db.RegExp({ regexp: '.*' + key, options: 'i', }) } ])).get({ success: res => { console.log(res) }, fail: err => { console.log(err) } }) [代码] key就是我们要搜索的关键字。主要是用到了数据库查询的where,or,get方法。 代码都给大家贴出来来,如果对云开发和云数据库还不是很了解的同学可以去翻看下我以前写的文章。
2019-11-06 - 小程序海报生成工具,可视化编辑直接生成代码使用,你的海报你自己做主
开门见山 工具地址 点我直达>>painter-custom-poster 由于挂载在github page上,打开速度会慢一些,请耐心等待或自行解决git网速问题 背景 在做小程序时候,我们经常会有一个需求,需要将小程序分享到朋友圈,但是朋友圈是不允许直接分享小程序,那我们还有其他的办法解决吗?答案肯定是有的,即 canvas 生成个性化海报分享图片到朋友圈 分析 小程序中有大量的生成图片需求,但是使用过 canvas 的人,都会发现一些难以预料的问题>>有关小程序的坑 直接在 canvas 上绘制图形,对于普通开发者来说代码会特别凌乱并且难以维护,经常会花费很久的时间去优化代码 不同的环境渲染问题,例如在开发者工具看起来好好的,一到 Android 真机,就出现图片不显示,位置不对应等等问题 解决 那可不可以开发一款生成海报的插件库呢? 首先,只需要提供一份简单的参数配置文件即可 解决掉小程序Canvas遇到的一些大大小小的坑 有严苛的测试环节,解决各种环境和各种机型遇到的问题,并提供稳定的线上版本 长期维护,并有专人更新迭代更新颖的功能 以上的要求当然是可以的,曾经的我也想尝试开发一款出来,但是后来尝试了几款现成的工具之后就放弃了,毕竟轮子这个东西,是需要不断维护更新的,另外已经有这么多优秀现成的插件了,我为何还要费力去写呢,贡献代码岂不更美哉,以下是我收集的几款 小程序生成图片库,轻松通过 json 方式绘制一张可以发到朋友圈的图片>>Painter 小程序组件-小程序海报组件>>wxa-plugin-canvas 微信小程序:一个 json 帮你完成分享朋友圈图片>>mp_canvas_drawer 我想干什么 唠了这么多,好像提供给大家插件就没我什么事情了…想走是不可能的 为了能够制作出更酷炫的海报,我思考了许久 虽然有了插件后,只需要提供配置代码就能够制作出一款海报来,但是我发现还是有些许问题 制作海报效率还是不够高,微调一个元素的大小和位置,就需要不断的修改保存代码,等待片刻,查看效果,真的烦 一个小小的位置调整可能就需要来回调整无数次,这种最简单的机械化劳动,这辈子是不可能的 拿着完美的稿子,递给设计师看,这个位置不对,这个线太粗,这个颜色太重…你信不信我打死你 对于一些精美复杂的海报,实现起来真的不太现实 那我需要怎么做呢,请点击这个链接体验>>painter-custom-poster 点击左侧例子展示中的任意一个例子,然后导入代码就能看到效果图,这下你应该能猜到了我的想法了 如何实现 刚开始我想用简单的html和css加拖动功能实现,通过简单尝试之后就放弃了,因为这个功能真的太复杂了,简单的工具肯定是不行的 中间这个计划停滞了很长时间,一度已经放弃 直到发现了这个库fabric.js,真的太太优秀了,赞美之词无以言表,唯一的缺点就是中文教程太少,必须生啃英文加谷歌翻译 fabric介绍,你可以很容易地创建任何一个简单的形状,复杂的形状,图像;将它们添加到画布中,并以任何你想要的方式进行修改:位置、尺寸、角度、颜色、笔画、不透明度等 How To Use 目前工具一共分成4部分 例子展示 用来将一些用户设计的精美海报显示出来,通过点击对应的例子并将代码导入画布中 画布区 显示真实的海报效果,画布里添加的元素,都可以直接用鼠标进行拖动,旋转,缩放操作 操作区 第一排四个按钮 复制代码 将画布的展示效果转化成小程序海报插件库所需要的json配置代码,目前我使用的是Painter库,默认会转化成这个插件的配置代码,将代码直接复制到card.js即可 查看代码 这个功能用不用无所谓,可以直观的看到生成的代码 导出json 将画布转化成fabric所需要的json代码,方便将自己设计的海报代码保存下来 导入json 将第3步导出的json代码导入,会在画布上显示已设计的海报样式 第二排五个按钮 画布 画布的属性参数 详解见下方 文字 添加文字的属性参数 详解见下方 矩形 添加矩形的属性参数 详解见下方 图片 添加图片的属性参数 详解见下方 二维码 添加二维码的属性参数 详解见下方 第三排 各种元素的详细设置参数 激活区 激活对象是指鼠标点击画布上的元素,该对象会被蓝色的边框覆盖,此时该对象被激活,可以执行拖动 旋转 缩放等操作 激活区只有对象被激活才会出来,用来设置激活对象的各种配置参数,修改value值后,实时更新当前激活对象的对应状态,点击其他区域,此模块将隐藏 快捷键 ‘←’ 左移一像素 ‘→’ 右移一像素 ‘↑’ 上移一像素 ‘↓’ 下移一像素 ‘ctrl + z’ 撤销 ‘ctrl + y’ 恢复 ‘delete’ 删除 ‘[’ 提高元素的层级 ‘]’ 降低元素的层级 布局属性 通用布局属性 属性 说明 默认 rotate 旋转,按照顺时针旋转的度数 0 width、height view 的宽度和高度 top、left 如 css 中为 absolute 布局时的作用 0 background 背景颜色 rgba(0,0,0,0) borderRadius 边框圆角 0 borderWidth 边框宽 0 borderColor 边框颜色 #000000 shadow 阴影 ‘’ shadow 可以同时修饰 image、rect、text 等 。在修饰 text 时则相当于 text-shadow;修饰 image 和 rect 时相当于 box-shadow 使用方法: [代码]shadow: 'h-shadow v-shadow blur color'; h-shadow: 必需。水平阴影的位置。允许负值。 v-shadow: 必需。垂直阴影的位置。允许负值。 blur: 必需。模糊的距离。 color: 必需。阴影的颜色。 举例: shadow:10 10 5 #888888 [代码] 渐变色支持 你可以在画布的 background 属性中使用以下方式实现 css 3 的渐变色,其中 radial-gradient 渐变的圆心为 中点,半径为最长边,目前不支持自己设置。 [代码]linear-gradient(-135deg, blue 0%, rgba(18, 52, 86, 1) 20%, #987 80%) radial-gradient(rgba(0, 0, 0, 0) 5%, #0ff 15%, #f0f 60%) [代码] !!!注意:颜色后面的百分比一定得写。 画布属性 属性 说明 默认 times 控制生成插件代码的宽度大小,比如画布宽100,times为2,生成的值为200 1 文字属性 属性名称 说明 默认值 text 字体内容 别跟我谈感情,谈感情伤钱 maxLines 最大行数 不限,根据 width 来 lineHeight 行高(上下两行文字baseline的距离) 1.3 fontSize 字体大小 30 color 字体颜色 #000000 fontWeight 字体粗细。仅支持 normal, bold normal textDecoration 文本修饰,支持none underline、 overline、 linethrough none textStyle fill: 填充样式,stroke:镂空样式 fill fontFamily 字体 sans-serif textAlign 文字的对齐方式,分为 left, center, right left 备注: fontFamily,工具中的第一个例子支持文字字体,但是导入小程序为什么看不到呢,小程序官网加载网络字体方法>> 加载字体教程>> 文字高度 是maxLines lineHeight2个字段一起计算出来的 图片属性 属性 说明 默认 url 图片路径 mode 图片裁剪、缩放的模式 aspectFill mode参数详解 scaleToFill 缩放图片到固定的宽高 aspectFill 图片裁剪显示对应的宽高 auto 自动填充 宽度全显示 高度自适应居中显示 Tips(一定要看哦~) 本工具不考虑兼容性,如发现不兼容请使用google浏览器 painter现在只支持这几种图形,所以暂不支持圆,线等 如果编辑过程,一个元素被挡住了,无法操作,请选择对象并通过[ ]快捷键提高降低元素的层级 文字暂不支持直接缩放操作,因为文字大小和元素高度不容易计算,可以通过修改激活栏目maxLines lineHeight fontSize值来动态改变元素 如发现导出的代码一个元素被另一个元素挡住了,请手动调整元素的位置,json数组中元素越往后层级显示就越高,由于painter没有提供层级参数,所以目前只能这样做 本工具导出代码全是以px为单位,为什么不支持rpx, 因为painter在rpx单位下,阴影和边框宽会出现大小计算问题,由于原例子没有提供px生成图片方案,可以下载我这里修改过的demo>>Painter即可解决 文本宽度随着字数不同而动态变化,想在文本后面加个图标根据文本区域长度布局, 请参考Painter文档这块教程直接修改源码 由于本工具开发有些许难度,如出现bug,建议或者使用上的问题,请提issue,源码地址>>painter-custom-poster 海报贡献 如果你设计的海报很好看,并且愿意开源贡献,可以贡献你的海报代码和缩略图,例子代码文件在example中,按顺序排列,例如现在库里例子是example2.js,那你添加example3.js和example3.jpg图片,事例可以参考一下文件夹中源码,然后在index.js中导出一下 导出代码 代码不要格式化,会报错,请原模原样复制到json字段里 生成缩略图 刚开始我想在此工具中直接生成图片,但是由于浏览器图片跨域问题导致报错失败 所以请去小程序中生成保存图片,图片质量设置0.2,并去tinypng压缩一下图片 找到painter.js,替换下边这个方法,可以生成0.2质量的图片,代码如下 [代码] saveImgToLocal() { const that = this; setTimeout(() => { wx.canvasToTempFilePath( { canvasId: 'k-canvas', fileType: 'jpg', quality: 0.2, success: function(res) { that.getImageInfo(res.tempFilePath); }, fail: function(error) { console.error(`canvasToTempFilePath failed, ${JSON.stringify(error)}`); that.triggerEvent('imgErr', { error: error }); } }, this ); }, 300); } [代码] TODO 颜色值选择支持调色板工具 文字padding支持 缩放位置弹跳问题优化 假如需求大的话,支持其他几款插件库代码的生成 ~ 创作不易,如果对你有帮助,请给个星星 star✨✨ 谢谢 ~
2019-09-27 - Webpack学习《接入Typescript》
TypeScript | 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持,设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。 传统调试TypeScript Typescript 代码需要通过构建将它转换成 JavaScript 代码后才能运行。 // show .ts 为 show 函数增加类型检查 export function show (content : string) { console.log('Hello ,' + content) } // main.ts 通过 ES6 模块规范导如 show 函数 import {show) from './show '; // 执行 show 函数 show ('Webpack '); 我们需要在当前项目的根目录下新建一个用于配置编译选项的 tsconfig.json 文件,编译器默认会读取和使用这个文件,配置文件的内容大致如下: [图片] 通过 npm install -g typescript 安装编译器到全局后,可以通过 tsc main. ts 命令编译 器到全局后,可以通过 tsc main. ts 命令编译 集成 Webpack 通过 Loader TypeScript 转换成 JavaScriptWebpack 在寻找模块对应的文件时需要尝试 ts 后缀。在运行构建前 npm i -D typescript awesome-typescript-loader 配置如下: const path = require('path') module.exports = { entry: './main', output: { filename: 'bundle.js', path: path.resolve(_dirname,'./dist') }, resolve: { // 先尝试以 ts 为后缀的 Typescript 源码文件 extensions : [ '.ts', '.js'] }, module: { rules: [ { test : /\.ts$/, loader: 'awesome-typescript-loader' } ] }, devtool:'so urce-map', // 输出 ur ce Map 以方便在浏览器里调试 Types cript 代码 } 总结由于对webpack比较感兴趣, 所以看了一些资料 《深入浅出Webpack.pdf--吴浩麟》后,决定打包配置引入TypeScript,小试一把。
2020-01-25 - 云开发应该怎么切换正式和测试环境
- 我现在云函数里面已经指定了正式的数据库环境,因为要上线了,肯定要改。。。 [图片] 但是我上线了之后,我在平时的开发中,要怎么切换到测试环境的云开发数据库啊!!! 我总不可能全部改成dev环境的数据库,然后部署上去,这样的话线上就炸了啊!????? - 希望提供的能力 请问现在有方法可以切换云开发的正式和测试环境的数据库吗????? 不然我现在每次调试就会往正式的云数据库插入脏数据,这很难受啊··· 拜托各位开发者看看,谢谢了。 ================================================================= 我看下面有一位评论说云函数不要指定,但是我试了还是不行,我先把截图放上来 云函数 [图片] 往云数据库插入一条数据 然后两个环境的云函数列表,都确认已经部署上去了 [图片] [图片] 在app.js里面初始化 [图片] 最后我点击自定义按钮触发云函数的时候,全部数据只在dev环境产生,在release根本没有。 [图片] [图片]
2019-06-04 - 借助云开发实现小程序模版消息推送(不用搭建服务器就可以实现微信消息推送)
上一节给大家将了借助云开发实现小程序支付功能,那么我们就要想了,能不能借助云开发实现小程序消息推送功能呢? 还别说,云开发还真能实现推送的功能。 一直关注我的同学肯定知道老师之前也写过借助java后台实现小程序消息推送的文章。 我们借助java后台虽然也能轻松的实现消息推送。但是呢?用java开发后台推送,必须要搭建服务器,学习java代码,部署java代码当然你就是做java开发的,或者学习过java,这没什么。 但是作为小程序开发人员来说,用java显得太重了。 传送门: 《借助小程序云开发实现小程序支付功能(含源码)》 《5行代码实现微信小程序模版消息推送 (含推送后台和小程序源码)》 下面就来教大家如何借助云开发实现小程序模版消息的推送功能。 老规矩,先看效果图 [图片] 下面来讲实现步骤 一,定义推送的云函数 由于我们的云推送功能只能在云函数里调用,所以我们这里必须要在云函数里实现推送功能。 1,首先我们定义一个云函数push0524。 如果你还不知道如何使用云开发,如何定义云函数,去翻下老师之前的文章。有写的。 [图片] 把完整的代码贴给大家 [代码]// 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init() // 云函数入口函数 exports.main = async(event, context) => { console.log(event) return sendTemplateMessage(event) } //小程序模版消息推送 async function sendTemplateMessage(event) { const { OPENID } = cloud.getWXContext() // 接下来将新增模板、发送模板消息、然后删除模板 // 注意:新增模板然后再删除并不是建议的做法,此处只是为了演示,模板 ID 应在添加后保存起来后续使用 const addResult = await cloud.openapi.templateMessage.addTemplate({ id: 'AT0002', keywordIdList: [3, 4, 5] }) const templateId = addResult.templateId //新增的模版id const sendResult = await cloud.openapi.templateMessage.send({ touser: OPENID, templateId, formId: event.formId, page: 'pages/index/index', data: { keyword1: { value: '云开发实现推送', }, keyword2: { value: '2019 年 5 月 24 日', }, keyword3: { value: '编程小石头', }, } }) //删除模版id await cloud.openapi.templateMessage.deleteTemplate({ templateId, }) return sendResult } [代码] 上面代码所实现的就是 1,创建模版,拿到模版id 2,使用模版ID,填充模版消息,发送模版 3,删除模版。 我们正常开发时,模版都是在小程序后台获取到的。这里是为例演示方便。所以正常开发时,只需要实现第二步就行了。 推送的关键代码就是这个方法: cloud.openapi.templateMessage.send 通常我们定义完push0524云函数以后,如果直接调用的话,会报错误的。 [图片] 来看下这个错误,看到红色框里的permission就知道,肯定是权限的问题。所以我们在定义完云函数以后,要在push0524云函数下面添加权限配置页面。如下图 [图片] 重要的就是这个: “templateMessage.send”, 推送权限。因为推送是云开发给我们提供的,我们这里调用时,必须配置相关权限,才能使用的。 到这里我们的推送功能就实现了。下面我们来验证下。 二,验证云开发推送 验证其实很简单,和我们之前的《5行代码实现微信小程序模版消息推送 (含推送后台和小程序源码)》 类似。只不过一个是在java后台推送,一个是在小城里推送。下面我们简单写个小程序里验证推送的demo。 功能很简单 1,获取formid,因为推送必须有formid的 2,点击调用push0524实现推送 [图片] 简单的贴下代码 [图片] [图片] 需要注意的一点:我们测试时,必须要真机测试。因为模拟器没法获取到formid的。 [图片] 我们在推送成功的success回调中打印下log。如果log中出现,send:ok字样,就代表我们推送成功了。来看下推送成功的效果。 微信聊天列表接收到了消息提醒 [图片] 消息内容 [图片] 到这里我们就用云开发实现完整的消息推送功能了。是不是很简单。 有任何关于编程的问题都可以加老师微信 2501902696(备注小程序)也可以找老师索要完整源码。 编程小石头码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑 视频讲解地址:https://edu.csdn.net/course/detail/24770
2019-06-11 - 云开发数据库导入csv文件时没办法控制字段类型
- 需求的场景描述(希望解决的问题) 云开发数据库导入csv文件时,平台会自动根据内容设置字段类型。 对于同一个字段(假定名称为“name”),当某一行的元素内容是“a”时,默认分配的字段类型是string,但另一行的元素内容是“1”时,默认分配的字段类型是number。这样会因字段类型不同导致根据该字段检索查询存在问题。 比如,我按照{name:"a"}可以检索到name为a的记录,但按照{name:"1"}无法检索到name为1的记录,只能按照{name:1}检索到name为1的记录。最终,因为同一字段在不同记录中的字段类型有差异,影响了数据检索。 - 希望提供的能力 建议:在云开发数据库导入csv文件时可以规范统一相同字段在不同记录中的字段类型。
2018-10-27 - 页面保存后不刷新,手动编译样式也没加载
[图片]
2019-08-19 - (已解决)小程序搜索查询数据库多字段正则匹配问题
where({ description1: db.RegExp({ regexp: keyValue, options: 'i', }) }) 如果还要以‘’或‘’的方式匹配description2该怎么写呢? 文档说不能用db.command。 求解?
2019-03-13 - 云函数获取用户手机号吗?
小程序通过云函数获得用户手机号码? 思路解析, [图片] 了解了小程序的加密方式,我们就可以自己去解密我们需要的信息。如:最困住我们的用户手机号码? 官方是有案例的,想更多学习可以给与参考,但是估计要多看几遍,有node基础的就比较好理解一些。 [图片] 下面是官网地址: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html#method-cloud 下面开始说我自己的方法; 1.首先构建云函数,需要两个云函数,一个用来解密,session_key,一个用来解密加密手机号码; [代码]//云函数:getSession; // 云函数入口文件 const cloud = require('wx-server-sdk') //npm install request-promise 通过终端下载npm install wx-server-sdk , const rp = require('request-promise'); cloud.init() // 云函数入口函数 exports.main = async (event, context) => { const _JSCODE = event.code const AccessToken_options = { method: 'GET', url: 'https://api.weixin.qq.com/sns/jscode2session', qs: { appid: '', //你的小程序appid; secret: '', //你的秘钥 grant_type: 'authorization_code', js_code: _JSCODE }, json: true }; const resultValue = await rp(AccessToken_options); return { resultValue } } [代码] 下载好需要的两个包,就可以对云函数初始化,执行npm init 有个起名字的环节,用过node的都知道,默认index.js,有个选择 [代码]package name: (gettoken) index.js version: (1.0.0) description: git repository: keywords: author: license: (ISC) About to write to D:\projects\zy_face_id_wxs\server\getToken\package.json: { "name": "index.js", "version": "1.0.0", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "request-promise": "^4.2.4", "wx-server-sdk": "^0.8.1" }, "devDependencies": {}, "description": "" } Is this OK? (yes) yes [代码] 这是初始化,终端的代码; 右键点击上传并部署到云端; 下面是客户端的代码; [代码] getPhoneNumber(e) { if (!e.detail.errMsg || e.detail.errMsg != "getPhoneNumber:ok") { wx.showModal({ content: '不能获取手机号码', showCancel: false }) return; } wx.showLoading({ title: '获取手机号中...', }) console.log(e) wx.login({ success(res) { if (res.code) { console.log(res.code) console.log(e.detail.iv) console.log(e.detail.encryptedData) wx.cloud.callFunction({ name: 'getSession', //调用云函数获取session_key; data: { code: res.code, }, success: res => { wx.hideLoading() // console.log(res.result.resultValue) var data = res.result.resultValue console.log(data) console.log(data.session_key) //获取到了session_key的值; }, fail: error => { console.log(error) } }) } } }) }, [代码] 2.构建第二个云函数 GetWX; [代码]// 云函数入口文件 const cloud = require('wx-server-sdk') // const requestpromise = require('request-promise'); var WXBizDataCrypt = require('./RdWXBizDataCrypt') // 用于手机号解密 cloud.init() exports.main = async (event, context) => { const session_key = event.session_key //appid写入你自己的appid,session_key 用第一个云函数的返回值; const pc = new WXBizDataCrypt(appid, session_key ) // -解密第一步 const data = pc.decryptData(event.encryptedData, event.iv) // 解密第二步 return { data } } [代码] 这个同样执行上面的步骤,npm install wx-server-sdk 和初始化npm init; 重点来了,解密所需要的js文件。 [图片]` 这两个文件已经上传到我的网盘里面,需要的请下载; https://pan.baidu.com/s/1VrS1gX_Bw3dKaZkQnNzy2A 提取码:cxnh; 格式和图片的保持一致,并上传到云端。 3.开始前端调用了; 代码如下; [代码]getPhoneNumber(e) { if (!e.detail.errMsg || e.detail.errMsg != "getPhoneNumber:ok") { wx.showModal({ content: '不能获取手机号码', showCancel: false }) return; } wx.showLoading({ title: '获取手机号中...', }) console.log(e) wx.login({ success(res) { if (res.code) { console.log(res.code) console.log(e.detail.iv) console.log(e.detail.encryptedData) wx.cloud.callFunction({ name: 'getSession', //调用云函数获取session_key; data: { code: res.code, }, success: res => { wx.hideLoading() var data = res.result.resultValue console.log(data) console.log(data.session_key) //获取到了session_key的值; const session_key=data.session_key wx.cloud.callFunction({ name:'getWX', //解析秘文,获得手机号码; data:{ session_key: session_key, encryptedData: e.detail.encryptedData, iv: e.detail.iv, }, success:res=>{ console.log(res) }, fail:err=>{ console.log(err) } }) }, fail: error => { console.log(error) } }) } } }) }, [代码] 4.输出的结果: [图片] 遇到问题了在私信问我,一一回答。
2019-07-17 - 小程序内用户帐号登录规范调整和优化建议
为更好地保护用户隐私信息,优化用户体验,平台将会对小程序内的帐号登录功能进行规范。本公告所称“帐号登录功能”是指开发者在小程序内提供帐号登录功能,包括但不限于进行的手机号登录,getuserinfo形式登录、邮箱登录等形式。具体规范要求如下: 1.服务范围开放的小程序 对于用户注册流程是对外开放、无需验证特定范围用户,且注册后即可提供线上服务的小程序,不得在用户清楚知悉、了解小程序的功能之前,要求用户进行帐号登录。 包括但不限于打开小程序后立即跳转提示登录或打开小程序后立即强制弹窗要求登录,都属于违反上述要求的情况; 以下反面示例,在用户打开小程序后立刻弹出授权登录页; [图片] 建议修改为如下正面示例形式:在体验小程序功能后,用户主动点击登录按钮后触发登录流程,且为用户提供暂不登录选项。 [图片] 2.服务范围特定的小程序 对于客观上服务范围特定、未完全开放用户注册,需通过更多方式完成身份验证后才能提供服务的小程序,可以直接引导用户进行帐号登录。例如为学校系统、员工系统、社保卡信息系统等提供服务的小程序; 下图案例为正面示例:校友管理系统,符合规范要求。 [图片] 3.仅提供注册功能小程序 对于线上仅提供注册功能,其他服务均需以其他方式提供的小程序,可在说明要求使用帐号登录功能的原因后,引导用户进行帐号注册或帐号登录。如ETC注册申请、信用卡申请; 如下反面示例,用户在进入时未获取任何信息,首页直接强制弹框要求登录注册ETC,这是不符合规范的。 [图片] 建议修改为如下正面示例所示形式:允许在首页说明注册功能后,提供登录或注册按钮供用户主动选择点击登录。 [图片] 4.提供可取消或拒绝登录选项 任何小程序调用帐号登录功能,应当为用户清晰提供可取消或拒绝的选项按钮,不得以任何方式强制用户进行帐号登录。 如下图所示反面示例,到需要登录环节直接跳转登录页面,用户只能选择点击登录或退出小程序,这不符合登录规范要求。 [图片] 建议修改为下图正面示例形式,在需帐号登录的环节,为用户主动点击登录,并提供可取消按钮,不强制登录。 [图片] 针对以上登录规范要求,平台希望开发者们能相应地调整小程序的帐号登录功能。如未满足登录规范要求,从2019年9月1日开始,平台将会在后续的代码审核环节进行规则提示和修改要求反馈。
2019-07-20 - 5行代码实现微信小程序模版消息推送 (含推送后台和小程序源码)
由于小程序2020年1月10日以后改模板消息为订阅消息,所以我写了一篇新的文章来更新这个知识点 《小程序订阅消息推送(含源码)java实现小程序推送,springboot实现微信消息推送》 我们在做小程序开发时,消息推送是不可避免的。今天就来教大家如何实现小程序消息推送的后台和前台开发。源码会在文章末尾贴出来。 其实我之前有写过一篇:《springboot实现微信消息推送,java实现小程序推送,含小程序端实现代码》 但是有同学反应这篇文章里的代码太繁琐,接入也比较麻烦。今天就来给大家写个精简版的,基本上只需要几行代码,就能实现小程序模版消息推送功能。 老规矩先看效果图 [图片] 这是我们最终推送给用户的模版消息。这是用户手机微信上显示的推送消息截图。 本节知识点 1,java开发推送后台 2,springboot实现推送功能 3,小程序获取用户openid 4,小程序获取fromid用来推送 先来看后台推送功能的实现 只有下面一个简单的PushController类,就可以实现小程序消息的推送 [图片] 再来看下PushController类,你没看错,实现小程序消息推送,就需要下面这几行代码就可以实现了。 [图片] 由于本推送代码是用springboot来实现的,下面就来简单的讲下。我我们需要注意的几点内容。 1,需要在pom.xml引入一个三方类库(推送的三方类库) [图片] pom.xml的完整代码如下 [代码]<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.qcl</groupId> <artifactId>wxapppush</artifactId> <version>0.0.1-SNAPSHOT</version> <name>wxapppush</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--微信小程序模版推送--> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-miniapp</artifactId> <version>3.4.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> [代码] 其实到这里我们java后台的推送功能,就已经实现了。我们只需要运行springboot项目,就可以实现推送了。 下面贴出完整的PushController.java类。里面注释很详细了。 [代码]package com.qcl.wxapppush; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; import me.chanjar.weixin.common.error.WxErrorException; /** * Created by qcl on 2019-05-20 * 微信:2501902696 * desc: 微信小程序模版推送实现 */ @RestController public class PushController { @GetMapping("/push") public String push(@RequestParam String openid, @RequestParam String formid) { //1,配置小程序信息 WxMaInMemoryConfig wxConfig = new WxMaInMemoryConfig(); wxConfig.setAppid("XXX");//小程序appid wxConfig.setSecret("xxx");//小程序AppSecret WxMaService wxMaService = new WxMaServiceImpl(); wxMaService.setWxMaConfig(wxConfig); //2,设置模版信息(keyword1:类型,keyword2:内容) List<WxMaTemplateData> templateDataList = new ArrayList<>(2); WxMaTemplateData data1 = new WxMaTemplateData("keyword1", "获取老师微信"); WxMaTemplateData data2 = new WxMaTemplateData("keyword2", "2501902696"); templateDataList.add(data1); templateDataList.add(data2); //3,设置推送消息 WxMaTemplateMessage templateMessage = WxMaTemplateMessage.builder() .toUser(openid)//要推送的用户openid .formId(formid)//收集到的formid .templateId("eDZCu__qIz64Xx19dAoKg0Taf5AAoDmhUHprF6CAd4A")//推送的模版id(在小程序后台设置) .data(templateDataList)//模版信息 .page("pages/index/index")//要跳转到小程序那个页面 .build(); //4,发起推送 try { wxMaService.getMsgService().sendTemplateMsg(templateMessage); } catch (WxErrorException e) { System.out.println("推送失败:" + e.getMessage()); return e.getMessage(); } return "推送成功"; } } [代码] 看代码我们可以知道,我们需要做一些配置,需要下面信息 1,小程序appid 2,小程序AppSecret(密匙) 3,小程序推送模版id 4,用户的openid 5,用户的formid(一个formid只能用一次) 下面就是小程序部分,来教大家如何获取上面所需的5个信息。 1,appid和AppSecret的获取(登录小程序管理后台) [图片] 2,推送模版id [图片] 3,用户openid的获取,可以看下面的这篇文章,也可以看源码,这里不做具体讲解 小程序开发如何获取用户openid 4,获取formid [图片] 看官方文档,可以知道我们的formid有效期是7天,并且一个form_id只能使用一次,所以我们小程序端所需要做的就是尽可能的多拿些formid,然后传个后台,让后台存到数据库中,这样7天有效期内,想怎么用就怎么用了。 所以接下来要讲的就是小程序开发怎么尽可能多的拿到formid了 [图片] 看下官方提供的,只有在表单提交时把report-submit设为true时才能拿到formid,比如这样 [代码] <form report-submit='true' > <button form-type='submit'>获取formid</button> </form> [代码] 所以我们就要在这里下功夫了,既然只能在form组件获取,我们能不能把我们小程序里用到最多的地方用form来伪装呢。 下面简单写个获取formid和openid的完整示例,方便大家学习 效果图 [图片] 我们要做的就是点击获取formid按钮,可以获取到用户的formid和openid,正常我们开发时,是需要把openid和formid传给后台的,这里简单起见,我们直接用获取到的formid和openid实现推送功能 下面来看小程序端的实现代码 1,index.wxml [图片] 2,index.js [图片] 到这里我们小程序端的代码也实现了,接下来测试下推送。 [代码]formid: 6ee9ce80c1ed4a2f887fccddf87686eb openid o3DoL0Uusu1URBJK0NJ4jD1LrRe0 [代码] [图片] 可以看到我们用了上面获取到的openid和formid做了一次推送,显示推送成功 [图片] [图片] 到这里我们小程序消息推送的后台和小程序端都讲完了。 这里有两点需要大家注意 1,推送的openid和formid必须对应。 2,一个formid只能用一次,多次使用会报一下错误。 [代码]{"errcode":41029,"errmsg":"form id used count reach limit hint: [ssun8a09984113]"} [代码] 编程小石头,码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑。 这里就不单独贴出源码下载链接了,大家感兴趣的话,可以私信我,或者在底部留言,我会把源码下载链接贴在留言区。 单独找我要源码也行(微信2501902696) 视频讲解:https://edu.csdn.net/course/detail/23750 源码链接:https://github.com/qiushi123/wxapppush
2020-01-08 - 借助小程序云开发实现小程序支付功能(含源码)
我们在做小程序支付相关的开发时,总会遇到这些难题。小程序调用微信支付时,必须要有自己的服务器,有自己的备案域名,有自己的后台开发。这就导致我们做小程序支付时的成本很大。本节就来教大家如何使用小程序云开发实现小程序支付功能的开发。不用搭建自己的服务器,不用有自己的备案域名。只需要简简单单的使用小程序云开发。 老规矩先看效果图: [图片] 本节知识点 1,云开发的部署和使用 2,支付相关的云函数开发 3,商品列表 4,订单列表 5,微信支付与支付成功回调 支付成功给用户发送推送消息的功能会在后面讲解。 下面就来教大家如何借助云开发使用小程序支付功能。 支付所需要用到的配置信息 1,小程序appid 2,云开发环境id 3,微信商户号 4,商户密匙 一,准备工作 1,已经申请小程序,获取小程序 AppID 和 Secret 在小程序管理后台中,【设置】 →【开发设置】 下可以获取微信小程序 AppID 和 Secret。 [图片] 2,微信支付商户号,获取商户号和商户密钥在微信支付商户管理平台中,【账户中心】→【商户信息】 下可以获取微信支付商户号。 [图片] 在【账户中心】 ‒> 【API安全】 下可以设置商户密钥。 [图片] 这里特殊说明下,个人小程序是没有办法使用微信支付的。所以如果想使用微信支付功能,必须是非个人账号(当然个人可以办个体户工商执照来注册非个人小程序账号) 3,微信开发者 IDE https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 4,开通小程序云开发功能:https://edu.csdn.net/course/play/9604/204526 二,商品列表的实现 效果图如下,由于本节重点是支付的实现,所以这里只简单贴出关键代码。 [图片] wxml布局如下: [代码]<view class="container"> <view class="good-item" wx:for="{{goods}}" wx:key="*this" ontap="getDetail" data-goodid="{{item._id}}"> <view class="good-image"> <image src="{{pic}}"></image> </view> <view class="good-detail"> <view class="title">商品: {{item.name}}</view> <view class="content">价格: {{item.price / 100}} 元 </view> <button class="button" type="primary" bindtap="makeOrder" data-goodid="{{item._id}}" >下单</button> </view> </view> </view> [代码] 我们所需要做的就是借助云开发获取云数据库里的商品信息,然后展示到商品列表,关于云开发获取商品列表并展示本节不做讲解(感兴趣的同学可以翻看我的历史博客,有写过的) 也有视频讲解: https://edu.csdn.net/course/detail/9604 [图片] 三,支付云函数的创建 首先看下我们支付云函数都包含那些内容 [图片] 简单先讲解下每个的用处 config下的index.js是做支付配置用的,主要配置支付相关的账号信息 lib是用的第三方的支付库,这里不做讲解。 重点讲解的是云函数入口 index.js 下面就来教大家如何去配置 1,配置config下的index.js, 这一步所需要做的就是把小程序appid,云开发环境ID,商户id,商户密匙。填进去。 [图片] 2,配置入口云函数 [图片] 详细代码如下,代码里注释很清除了,这里不再做单独讲解: [代码]const cloud = require('wx-server-sdk') cloud.init() const app = require('tcb-admin-node'); const pay = require('./lib/pay'); const { mpAppId, KEY } = require('./config/index'); const { WXPayConstants, WXPayUtil } = require('wx-js-utils'); const Res = require('./lib/res'); const ip = require('ip'); /** * * @param {obj} event * @param {string} event.type 功能类型 * @param {} userInfo.openId 用户的openid */ exports.main = async function(event, context) { const { type, data, userInfo } = event; const wxContext = cloud.getWXContext() const openid = userInfo.openId; app.init(); const db = app.database(); const goodCollection = db.collection('goods'); const orderCollection = db.collection('order'); // 订单文档的status 0 未支付 1 已支付 2 已关闭 switch (type) { // [在此处放置 unifiedorder 的相关代码] case 'unifiedorder': { // 查询该商品 ID 是否存在于数据库中,并将数据提取出来 const goodId = data.goodId let goods = await goodCollection.doc(goodId).get(); if (!goods.data.length) { return new Res({ code: 1, message: '找不到商品' }); } // 在云函数中提取数据,包括名称、价格才更合理安全, // 因为从端里传过来的商品数据都是不可靠的 let good = goods.data[0]; // 拼凑微信支付统一下单的参数 const curTime = Date.now(); const tradeNo = `${goodId}-${curTime}`; const body = good.name; const spbill_create_ip = ip.address() || '127.0.0.1'; // 云函数暂不支付 http 触发器,因此这里回调 notify_url 可以先随便填。 const notify_url = 'http://www.qq.com'; //'127.0.0.1'; const total_fee = good.price; const time_stamp = '' + Math.ceil(Date.now() / 1000); const out_trade_no = `${tradeNo}`; const sign_type = WXPayConstants.SIGN_TYPE_MD5; let orderParam = { body, spbill_create_ip, notify_url, out_trade_no, total_fee, openid, trade_type: 'JSAPI', timeStamp: time_stamp, }; // 调用 wx-js-utils 中的统一下单方法 const { return_code, ...restData } = await pay.unifiedOrder(orderParam); let order_id = null; if (return_code === 'SUCCESS' && restData.result_code === 'SUCCESS') { const { prepay_id, nonce_str } = restData; // 微信小程序支付要单独进地签名,并返回给小程序端 const sign = WXPayUtil.generateSignature({ appId: mpAppId, nonceStr: nonce_str, package: `prepay_id=${prepay_id}`, signType: 'MD5', timeStamp: time_stamp }, KEY); let orderData = { out_trade_no, time_stamp, nonce_str, sign, sign_type, body, total_fee, prepay_id, sign, status: 0, // 订单文档的status 0 未支付 1 已支付 2 已关闭 _openid: openid, }; let order = await orderCollection.add(orderData); order_id = order.id; } return new Res({ code: return_code === 'SUCCESS' ? 0 : 1, data: { out_trade_no, time_stamp, order_id, ...restData } }); } // [在此处放置 payorder 的相关代码] case 'payorder': { // 从端里出来相关的订单相信 const { out_trade_no, prepay_id, body, total_fee } = data; // 到微信支付侧查询是否存在该订单,并查询订单状态,看看是否已经支付成功了。 const { return_code, ...restData } = await pay.orderQuery({ out_trade_no }); // 若订单存在并支付成功,则开始处理支付 if (restData.trade_state === 'SUCCESS') { let result = await orderCollection .where({ out_trade_no }) .update({ status: 1, trade_state: restData.trade_state, trade_state_desc: restData.trade_state_desc }); let curDate = new Date(); let time = `${curDate.getFullYear()}-${curDate.getMonth() + 1}-${curDate.getDate()} ${curDate.getHours()}:${curDate.getMinutes()}:${curDate.getSeconds()}`; } return new Res({ code: return_code === 'SUCCESS' ? 0 : 1, data: restData }); } case 'orderquery': { const { transaction_id, out_trade_no } = data; // 查询订单 const { data: dbData } = await orderCollection .where({ out_trade_no }) .get(); const { return_code, ...restData } = await pay.orderQuery({ transaction_id, out_trade_no }); return new Res({ code: return_code === 'SUCCESS' ? 0 : 1, data: { ...restData, ...dbData[0] } }); } case 'closeorder': { // 关闭订单 const { out_trade_no } = data; const { return_code, ...restData } = await pay.closeOrder({ out_trade_no }); if (return_code === 'SUCCESS' && restData.result_code === 'SUCCESS') { await orderCollection .where({ out_trade_no }) .update({ status: 2, trade_state: 'CLOSED', trade_state_desc: '订单已关闭' }); } return new Res({ code: return_code === 'SUCCESS' ? 0 : 1, data: restData }); } } } [代码] 其实我们支付的关键功能都在上面这些代码里面了。 [图片] 再来看下,支付的相关流程截图 [图片] 上图就涉及到了我们的订单列表,支付状态,支付成功后的回调。 今天就先讲到这里,后面会继续给大家讲解支付的其他功能。比如支付成功后的消息推送,也是可以借助云开发实现的。 由于源码里涉及到一些私密信息,这里就不单独贴出源码下载链接了,大家感兴趣的话,可以私信我,或者在底部留言。单独找我要源码也行(微信2501902696) 视频讲解地址:https://edu.csdn.net/course/detail/24770
2019-06-11 - 假期为啥不用加班,因为小程序云开发上线了这个功能!
作者:Yellowsun 清明小长假就要来了,今天你可以按时下班吗? 开发阿杰早在假期前就计划好了和女友的巴厘岛之旅,也提前订好了机票。可偏偏就在放假前一天,因公司接待需要得紧急上线一个访客预约的小程序解决自主预约及访客通知的需求,由于没有通过小程序发通知的经验沉淀,从阅读文档到产品发布可能需要耗费不少的时间,这使阿杰犯了难,原定于19:00起飞的飞机,他还能赶上吗? 好在继云函数、云存储、云数据库之后,又一提高开发效率的神器——云调用上线了! 啥是云调用? 云调用简单来说是一种免Token调用微信API的能力。传统的微信小程序开发,如果需要调用服务端的API,需要拿着 appid 和 appsecret 换取微信小程序全局唯一后台接口调用凭证 access_token ,而且有效期仅有2小时,有了这个凭证才能开始调用诸如模版消息、客服消息等API。而云调用的诞生,大大简化了调用微信API的鉴权步骤,实现一行代码即调即用。 为什么要用云调用? 微信小程序使用云调用能力后,开发者能够—— 1、一行代码调用API 云调用允许在没有获取 access_token 的情况下调用大部分小程序服务端的API,开发者只需关心业务逻辑本身及调用API的时机,真正实现一行代码调用API。 2、无需担心凭证安全 支持云调用的接口无需获取 access_token 即可调用,换句话说,就是开发者无需关心 access_token 的保管及失效问题,即可获得天然、安全、可靠的接口调用条件,一切接口调用的鉴权机制都交由云开发处理。 如何使用云调用? 阿杰阅读了云调用的文档后,瞬间理解了云调用的实现方法。结合实际产品需求,公司预期的小程序需要在用户输入预约信息提交后,向用户推送模板消息进行通知。 [图片] 就微信小程序推送模板消息,传统实现路径:用户预约成功 - 检查 access_token 是否在有效期内 - 获取 access_token - 调用 templateMessage.send - 推送模板消息。 而云调用实现路径:用户预约成功 - 调用templateMessage.send - 推送模板消息,完全无需关心 access_token 的获取、保管、失效等问题。 结合 wx-server-sdk 提供的 getWXContext 方法获取登录用户的 openid ,调用 templateMessage.send 这个方法,传入接收者 openid 、模板消息内容、模板消息id等参数,即可完成模板消息的下发。发送模板消息的核心代码如下: [图片] 将写好的云函数部署至云端,当用户预约成功后就能收到模板消息通知了。至此大功告成,自测无误提审! [图片] 阿杰巧借云开发的云调用能力,免除了 access_token 获取、校验、保管等相关处理机制的设计,在不到一下午的时间完成了整个项目。最后也如期赶到了机场,阿杰将经过转述给了在机场没等多久的女友,看着女友膜拜的眼神,阿杰拉着女友的手开心地走向了登机口... (故事纯属虚构,如有雷同... 那就是雷同) 巧用云开发,不加班不是梦 云调用的上线将进一步降低微信小程序的开发门槛,提升开发效率。免 access_token 调用 API ,距离早点下班又进了一步! [图片] 除了云调用外,云开发同时还免费提供云函数、云数据库、云存储等Serverless(无服务器计算)能力,助力微信小程序开发者! [图片] (微信开发者工具内置的云开发入口) 目前 微信开发者工具版本 >= 1.02.1903251 且 云函数 wx-server-sdk >= 0.4.0 的开发者可以直接使用云调用能力,具体使用方法详见《微信小程序开发文档》。
2019-04-09 - showModal提供的属性太少了,button需要支持open-type啊
- 提取封装的公共方法弹窗种的按钮要提供分享功能,现在分享需要使用open-type属性,但showModal方法没有提供设置按钮open-type属性的口子 - 需要提供设置wx.showModal弹窗中button的open-type属性的入口 为什么不是直接一个confirmButton的属性,然后里面的属性直接整个应用到button上……结果就是连open-type属性的没法设置……随便一进阶点的需求就要自定义弹窗,然后就搞得更麻烦了……
2018-05-05 - 云开发支付的代码,有需要的进。
真机测试已通过。你照抄就行,保证可通过。 最新完美版本可供参考: https://developers.weixin.qq.com/community/develop/article/doc/0004c4a50a03107eaa79f03cc56c13 小程序端: wx.cloud.callFunction({ name: 'getPay' , data: { total_fee: parseFloat(0.01).toFixed(2) * 100, attach: 'anything', body: 'whatever' } }) .then( res => { wx.requestPayment({ appId: res.result.appid, timeStamp: res.result.timeStamp, nonceStr: res.result.nonce_str, package: 'prepay_id=' + res.result.prepay_id, signType: 'MD5', paySign: res.result.paySign, success: res => { console.log(res) } }) }) 云函数:getPay getPay目录下共两个文件: 1、index.js 2、package.json index.js代码如下: const key = "YOURKEY1234YOURKEY1234YOURKEY123"//这是商户的key,不是小程序的密钥,32位。 const mch_id = "1413090000" //你的商户号 //将以上的两个参数换成你的,然后以下可以不用改一个字照抄 const rp = require('request-promise') const crypto = require('crypto') function paysign({ ...args }) { let sa = [] for (let k in args) sa.push( k + '=' + args[k]) sa.push( 'key=' + key) return crypto.createHash('md5').update(sa.join('&'), 'utf8').digest('hex').toUpperCase() } exports.main = async (event, context) => { const appid = event.userInfo.appId const openid = event.userInfo.openId const attach = event.attach const body = event.body const total_fee = event.total_fee const notify_url = "https://whatever.com/notify" const spbill_create_ip = "118.89.40.200" const nonce_str = Math.random().toString(36).substr(2, 15) const timeStamp = parseInt(Date.now() / 1000) + '' const out_trade_no = "otn" + nonce_str + timeStamp let formData = "<xml>" formData += "<appid>" + appid + "</appid>" formData += "<attach>" + attach + "</attach>" formData += "<body>" + body + "</body>" formData += "<mch_id>" + mch_id + "</mch_id>" formData += "<nonce_str>" + nonce_str + "</nonce_str>" formData += "<notify_url>" + notify_url + "</notify_url>" formData += "<openid>" + openid + "</openid>" formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>" formData += "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" formData += "<total_fee>" + total_fee + "</total_fee>" formData += "<trade_type>JSAPI</trade_type>" formData += "<sign>" + paysign({ appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type: 'JSAPI' }) + "</sign>" formData += "</xml>" let res = await rp({ url: "https://api.mch.weixin.qq.com/pay/unifiedorder", method: 'POST',body: formData}) let xml = res.toString("utf-8") if (xml.indexOf('prepay_id')<0) return xml let prepay_id = xml.split("<prepay_id>")[1].split("</prepay_id>")[0].split('[')[2].split(']')[0] let paySign = paysign({ appId: appid, nonceStr: nonce_str, package: ('prepay_id=' + prepay_id), signType: 'MD5', timeStamp: timeStamp }) return { appid, nonce_str, timeStamp, prepay_id, paySign } } package.json 代码如下: { "name": "getPay", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "youself", "license": "ISC", "dependencies": { "crypto": "^1.0.1", "request-promise": "^4.2.2" } } 最后选择:上传和部署:云端安装依赖。
2019-12-14 - 小程序云开发上传函数失败
上传函数失败为什么 ?[图片]
2018-11-06