
【申精】swiper + scroll-view 实现下拉刷新
各位D友大家好,相信大家对uniapp都非常的喜欢,非常好的设计,能省去我们很多的开发成本。但是因为有一些是不尽人意的,比如我们想要实现的和原生效果接近的滑动tab 下拉刷新,官方给出的示例中无法支持下拉刷新。在此我放出一个的解决方案,可以实现我们要的效果。但是毕竟是投机取巧,还是希望官方可以出个单独的插件。闲话少说,开始~
首先我们知道 原生下拉刷新的出发是根据page的scrollTop触发的。当scrollTop为0时才开始触发。那么,我们就可以根据这个来实现了
第一步,页面构建完成之后开始计算你的scroll-view需要的高度,scroll-view tabList 的高度要求超出屏幕可视高度1个标准单位(太多体验不好)。
第二步,添加scroll-view 的scroll事件,获取scrollTop值。判断当scrollTop大于0的时候调用pageScrollTo方法将page 的 scroll 拉至1
这样scroll-view在下拉的时候就不会触发系统下拉刷新的动作
第三步,添加scroll-view 的scrolltoupper事件并设置属性upper-threshold=0,事件触发时调用pageScrollTo方法将page 的 scroll 拉至0就能正常的使用下拉刷新了。
第四步,在tab切换时也判断当前scroll的scrollTop,然后调整当前tab的page scrollTop。
至此,swiper scroll-view 下拉刷新 就完成了,是不是很简单。
缺点:头部tabBar会上下1个标准单位的跳动(不过能接受,不是很影响)
下面贴出我的代码:

效果演示:
各位D友大家好,相信大家对uniapp都非常的喜欢,非常好的设计,能省去我们很多的开发成本。但是因为有一些是不尽人意的,比如我们想要实现的和原生效果接近的滑动tab 下拉刷新,官方给出的示例中无法支持下拉刷新。在此我放出一个的解决方案,可以实现我们要的效果。但是毕竟是投机取巧,还是希望官方可以出个单独的插件。闲话少说,开始~
首先我们知道 原生下拉刷新的出发是根据page的scrollTop触发的。当scrollTop为0时才开始触发。那么,我们就可以根据这个来实现了
第一步,页面构建完成之后开始计算你的scroll-view需要的高度,scroll-view tabList 的高度要求超出屏幕可视高度1个标准单位(太多体验不好)。
第二步,添加scroll-view 的scroll事件,获取scrollTop值。判断当scrollTop大于0的时候调用pageScrollTo方法将page 的 scroll 拉至1
这样scroll-view在下拉的时候就不会触发系统下拉刷新的动作
第三步,添加scroll-view 的scrolltoupper事件并设置属性upper-threshold=0,事件触发时调用pageScrollTo方法将page 的 scroll 拉至0就能正常的使用下拉刷新了。
第四步,在tab切换时也判断当前scroll的scrollTop,然后调整当前tab的page scrollTop。
至此,swiper scroll-view 下拉刷新 就完成了,是不是很简单。
缺点:头部tabBar会上下1个标准单位的跳动(不过能接受,不是很影响)
下面贴出我的代码:
效果演示:
收起阅读 »
PHP编程中使用CURL发送HTTP请求的基本流程
在PHP编程中,有时候需要编程技术人员使用CURL的PHP扩展完成一个HTTP请求的发送,对于这个操作来说,很多初学者都会遇到很多苦难,那么下面就来为大家讲解一下。一般有以下几个步骤:
1. 初始化连接句柄;
2. 设置CURL选项;
3. 执行并获取结果;
4. 释放VURL连接句柄。
下面的程序片段是使用CURL发送HTTP的典型过程
上述代码中使用到了四个函数
· curl_init() 和 curl_close() 分别是初始化CURL连接和关闭CURL连接,都比较简单。
· curl_exec() 执行CURL请求,如果没有错误发生,该函数的返回是对应URL返回的数据,以字符串表示满意;如果发生错误,该函数返回 FALSE。需要注意的是,判断输出是否为FALSE用的是全等号,这是为了区分返回空串和出错的情况。
· CURL函数库里最重要的函数是curl_setopt(),它可以通过设定CURL函数库定义的选项来定制HTTP请求。上述代码片段中使用了三个重要的选项:
1. CURLOPT_URL 指定请求的URL;
2. CURLOPT_RETURNTRANSFER 设置为1表示稍后执行的curl_exec函数的返回是URL的返回字符串,而不是把返回字符串定向到标准输出并返回TRUE;
CURLLOPT_HEADER设置为0表示不返回HTTP头部信息。
获取CURL请求的输出信息
在curl_exec()函数执行之后,可以使用curl_getinfo()函数获取CURL请求输出的相关信息,示例代码如下:
上述代码中curl_getinfo返回的是一个关联数组,包含以下数据:
· url:网络地址。
· content_type:内容编码。
· http_code:HTTP状态码。
· header_size:header的大小。
· request_size:请求的大小。
· filetime:文件创建的时间。
· ssl_verify_result:SSL验证结果。
· redirect_count:跳转计数。
· total_time:总耗时。
· namelookup_time:DNS查询耗时。
· connect_time:等待连接耗时。
· pretransfer_time:传输前准备耗时。
· size_uplpad:上传数据的大小。
· size_download:下载数据的大小。
· speed_download:下载速度。
· speed_upload:上传速度。
· download_content_length:下载内容的长度。
· upload_content_length:上传内容的长度。
· starttransfer_time:开始传输的时间表。
· redirect_time:重定向耗时。
curl_getinfo()函数还有一个可选择参数$opt,通过这个参数可以设置一些常量,对应到上术这个字段,如果设置了第二个参数,那么返回的只有指定的信息。例如设置$opt为CURLINFO_TOTAL_TIME,则curl_getinfo()函数只返回total_time,即总传输消耗的时间,在只需要关注某些传输信息时,设置$opt参数很有意义。
使用CURL发送GET请求
如何使用CURL来发送GET请求,发送GET请求的关键是拼装格式正确的URL。请求地址和GET数据由一个“?”分割,然后GET变量的名称和值用“=”分隔,各个GET名称和值由“&”连接。PHP为我们提供了一个函数专门用来拼装GET请求和数据部分——http_build_query,该函数接受一个关联数组,返回由该关联数据描述的GET请求字符串。使用这个函数,结合CURL发送HTTP请求的一般流程,我们封闭了一个发送GET请求的函数——doCurlGetRequest,具体代码如下:
使用CURL发送POST请求
可以使用CURL提供的选项CURLOPT_POSTFIELDS,设置该选项为POST字符串数据就可以把请求放在正文中。同样我们实现了一个发送POST请求的函数——doCurlPostRequest,代码如下:
好了,现在大家应该清楚如何操作了吧,如果还是存在问题的话可以咨询留言。本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处。
在PHP编程中,有时候需要编程技术人员使用CURL的PHP扩展完成一个HTTP请求的发送,对于这个操作来说,很多初学者都会遇到很多苦难,那么下面就来为大家讲解一下。一般有以下几个步骤:
1. 初始化连接句柄;
2. 设置CURL选项;
3. 执行并获取结果;
4. 释放VURL连接句柄。
下面的程序片段是使用CURL发送HTTP的典型过程
上述代码中使用到了四个函数
· curl_init() 和 curl_close() 分别是初始化CURL连接和关闭CURL连接,都比较简单。
· curl_exec() 执行CURL请求,如果没有错误发生,该函数的返回是对应URL返回的数据,以字符串表示满意;如果发生错误,该函数返回 FALSE。需要注意的是,判断输出是否为FALSE用的是全等号,这是为了区分返回空串和出错的情况。
· CURL函数库里最重要的函数是curl_setopt(),它可以通过设定CURL函数库定义的选项来定制HTTP请求。上述代码片段中使用了三个重要的选项:
1. CURLOPT_URL 指定请求的URL;
2. CURLOPT_RETURNTRANSFER 设置为1表示稍后执行的curl_exec函数的返回是URL的返回字符串,而不是把返回字符串定向到标准输出并返回TRUE;
CURLLOPT_HEADER设置为0表示不返回HTTP头部信息。
获取CURL请求的输出信息
在curl_exec()函数执行之后,可以使用curl_getinfo()函数获取CURL请求输出的相关信息,示例代码如下:
上述代码中curl_getinfo返回的是一个关联数组,包含以下数据:
· url:网络地址。
· content_type:内容编码。
· http_code:HTTP状态码。
· header_size:header的大小。
· request_size:请求的大小。
· filetime:文件创建的时间。
· ssl_verify_result:SSL验证结果。
· redirect_count:跳转计数。
· total_time:总耗时。
· namelookup_time:DNS查询耗时。
· connect_time:等待连接耗时。
· pretransfer_time:传输前准备耗时。
· size_uplpad:上传数据的大小。
· size_download:下载数据的大小。
· speed_download:下载速度。
· speed_upload:上传速度。
· download_content_length:下载内容的长度。
· upload_content_length:上传内容的长度。
· starttransfer_time:开始传输的时间表。
· redirect_time:重定向耗时。
curl_getinfo()函数还有一个可选择参数$opt,通过这个参数可以设置一些常量,对应到上术这个字段,如果设置了第二个参数,那么返回的只有指定的信息。例如设置$opt为CURLINFO_TOTAL_TIME,则curl_getinfo()函数只返回total_time,即总传输消耗的时间,在只需要关注某些传输信息时,设置$opt参数很有意义。
使用CURL发送GET请求
如何使用CURL来发送GET请求,发送GET请求的关键是拼装格式正确的URL。请求地址和GET数据由一个“?”分割,然后GET变量的名称和值用“=”分隔,各个GET名称和值由“&”连接。PHP为我们提供了一个函数专门用来拼装GET请求和数据部分——http_build_query,该函数接受一个关联数组,返回由该关联数据描述的GET请求字符串。使用这个函数,结合CURL发送HTTP请求的一般流程,我们封闭了一个发送GET请求的函数——doCurlGetRequest,具体代码如下:
使用CURL发送POST请求
可以使用CURL提供的选项CURLOPT_POSTFIELDS,设置该选项为POST字符串数据就可以把请求放在正文中。同样我们实现了一个发送POST请求的函数——doCurlPostRequest,代码如下:
好了,现在大家应该清楚如何操作了吧,如果还是存在问题的话可以咨询留言。本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处。
收起阅读 »
APP不适配iphoneX【解决方法】
背景:
上个月打包好的app,在苹果商城上架被拒。原因:app不适配iphoneX。
因为iphoneX去除Home按键指示器,审核时底部样式缺失,该app不适配iphonex(ps:在查找了相关资料处理后,又重新打包审核,目前app上架中)。
解决方法:
manifest.json配置文件 ----> ‘代码视图’ ----> 'plus'下添加代码(添加安全区域):
"safearea":{
"background":"#fff",
"bottom":{
"offset":"auto"
}
},
保存后,重新打包审核即可。
背景:
上个月打包好的app,在苹果商城上架被拒。原因:app不适配iphoneX。
因为iphoneX去除Home按键指示器,审核时底部样式缺失,该app不适配iphonex(ps:在查找了相关资料处理后,又重新打包审核,目前app上架中)。
解决方法:
manifest.json配置文件 ----> ‘代码视图’ ----> 'plus'下添加代码(添加安全区域):
"safearea":{
"background":"#fff",
"bottom":{
"offset":"auto"
}
},
保存后,重新打包审核即可。
收起阅读 »
双标题,如何禁用原生标题栏【解决方法】
说明:
首先说明,官方建议隐藏HTML的头header,而不是隐藏wap2app的原生头。
因为wap2app的原生头渲染更快,页面加载时不会出现整屏白屏的情况。
情景:
但是wap站的header中已存在相关的逻辑,功能全部移到原生标题栏上很是麻烦。因此,我们为了解决双标题问题,需要禁止原生标题栏。
如何隐藏?
sitemap.json如下:
{
"global": {
"webviewParameter": {
"titleNView": false, //禁用原生标题栏
"statusbar": {
//系统状态栏样式(前景色)
"style": "dark",
"background": "#F7F7F7"
},
"appendCss": "",
"appendJs": ""
},
"easyConfig": {
"quit":{
"toast":{
"showFeedback": false
}
},
"open": {
"animation": {//窗口切换动画配置 参考文档 【http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/12750】 -> open.animation
"type": "pop-in", //窗口动画类型 默认为 slide-in-right
"duration": 300
}
}
}
},
"pages": [
{
"webviewId": "W2Ahello.wap2app.dcloud.io",//首页
"matchUrls": [
{
"href": "http://hello.wap2app.dcloud.io"
}, {
"href": "http://hello.wap2app.dcloud.io"
}
],
"webviewParameter": {
"titleNView": false,
"statusbar": {
//状态条背景色,
//首页不使用原生导航条,颜色值建议和global->webviewParameter->titleNView->backgroundColor颜色值保持一致
//若首页启用了原生导航条,则建议将首页的statusbar配置为false,这样状态条可以和原生导航条背景色保持一致;
"background": "#f7f7f7"
}
}
},
{//未适配的公共页面,可拦截原生下载和头部导航栏, 注:通配符的规则+放在最后一个节点才能达到适配所有未适配的公共页面效果,适配规则优先级为自上而下查找匹配规则
"webviewId": "common",
"matchUrls": [
{
"hostname": "R:.",
"pathname": "R:."
}
],
"webviewParameter": {
"titleNView":false,
"statusbar": {
"style":"dark",
//状态条背景色,
//首页不使用原生导航条,颜色值建议和global->webviewParameter->titleNView->backgroundColor颜色值保持一致
"background": "#F7F7F7"
}
},
"easyConfig": {
"quit":{
"toast":{
"showFeedback": false
}
},
"open": {
"animation": {//窗口切换动画配置 参考文档 【http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/12750】 -> open.animation
"type": "pop-in", //窗口动画类型 默认为 slide-in-right
"duration": 300
}
}
}
}
]
}
说明:
首先说明,官方建议隐藏HTML的头header,而不是隐藏wap2app的原生头。
因为wap2app的原生头渲染更快,页面加载时不会出现整屏白屏的情况。
情景:
但是wap站的header中已存在相关的逻辑,功能全部移到原生标题栏上很是麻烦。因此,我们为了解决双标题问题,需要禁止原生标题栏。
如何隐藏?
sitemap.json如下:
{
"global": {
"webviewParameter": {
"titleNView": false, //禁用原生标题栏
"statusbar": {
//系统状态栏样式(前景色)
"style": "dark",
"background": "#F7F7F7"
},
"appendCss": "",
"appendJs": ""
},
"easyConfig": {
"quit":{
"toast":{
"showFeedback": false
}
},
"open": {
"animation": {//窗口切换动画配置 参考文档 【http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/12750】 -> open.animation
"type": "pop-in", //窗口动画类型 默认为 slide-in-right
"duration": 300
}
}
}
},
"pages": [
{
"webviewId": "W2Ahello.wap2app.dcloud.io",//首页
"matchUrls": [
{
"href": "http://hello.wap2app.dcloud.io"
}, {
"href": "http://hello.wap2app.dcloud.io"
}
],
"webviewParameter": {
"titleNView": false,
"statusbar": {
//状态条背景色,
//首页不使用原生导航条,颜色值建议和global->webviewParameter->titleNView->backgroundColor颜色值保持一致
//若首页启用了原生导航条,则建议将首页的statusbar配置为false,这样状态条可以和原生导航条背景色保持一致;
"background": "#f7f7f7"
}
}
},
{//未适配的公共页面,可拦截原生下载和头部导航栏, 注:通配符的规则+放在最后一个节点才能达到适配所有未适配的公共页面效果,适配规则优先级为自上而下查找匹配规则
"webviewId": "common",
"matchUrls": [
{
"hostname": "R:.",
"pathname": "R:."
}
],
"webviewParameter": {
"titleNView":false,
"statusbar": {
"style":"dark",
//状态条背景色,
//首页不使用原生导航条,颜色值建议和global->webviewParameter->titleNView->backgroundColor颜色值保持一致
"background": "#F7F7F7"
}
},
"easyConfig": {
"quit":{
"toast":{
"showFeedback": false
}
},
"open": {
"animation": {//窗口切换动画配置 参考文档 【http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/12750】 -> open.animation
"type": "pop-in", //窗口动画类型 默认为 slide-in-right
"duration": 300
}
}
}
}
]
}
收起阅读 »
侃一侃WebSocket
今天不讲太多具体的技术,随便侃一侃websocket,想到哪说哪。
uniapp websocket体验demo:https://ext.dcloud.net.cn/plugin?id=1334
和comet相比
相比comet技术,websocket不仅节约了header的问题(websocket的head信息只有短短的2个字节)。更加重要的是是通信的稳定性,comet在遇到网络问题之后,想要在不刷新页面的情况下恢复通信,非常困难,而websocket中提供了onclose函数来处理断开网络后的情况,这为我们与服务器的通信提供了可靠的保障。在、github上有一个js库
(https://github.com/joewalnes/reconnecting-websocket)就是通过这种方式来处理websocket断网重连。
当然这么好用的websocket也不是没有它的问题,websocket目前来看最大的问题是浏览器的支持(幸好大部分的服务器软件在比较新的版本中都已经支持了websocket),ie直到10才开始支持这种协议,而且每个浏览器最近在升级浏览器的时候,都会对websocket做出细微的调整。而且,想象你打开一个页面,当这个页面打开websocket连接并且执行一个内部IP地址的端口扫描,如果端口扫描发现了内部网络上发现了一个开启的80端口,一个隧道就可能通过你的浏览器建立。这样做很可能最终绕过防火墙,并且允许访问内部内容。所以安全问题,也是websocket现在面临的一大隐患。
WebSocket是HTML5出的协议,也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)。
首先HTTP有 1.1 和 1.0 之说,也就是所谓的 keep-alive ,把多个HTTP请求合并为一个,但是 Websocket 其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充。有交集,但是并不是全部。
另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。通俗来说,你可以用HTTP协议传输非Html数据,就是这样。再简单来说,层级不一样。
WebSocket的协议是持久化的,而HTTP是非持久化的协议。
今天说到这里,关于WebSocket的下次我们接着聊。www.goeasy.io 这家是专门做WebSocket的,有兴趣可以关注一下。
今天不讲太多具体的技术,随便侃一侃websocket,想到哪说哪。
uniapp websocket体验demo:https://ext.dcloud.net.cn/plugin?id=1334
和comet相比
相比comet技术,websocket不仅节约了header的问题(websocket的head信息只有短短的2个字节)。更加重要的是是通信的稳定性,comet在遇到网络问题之后,想要在不刷新页面的情况下恢复通信,非常困难,而websocket中提供了onclose函数来处理断开网络后的情况,这为我们与服务器的通信提供了可靠的保障。在、github上有一个js库
(https://github.com/joewalnes/reconnecting-websocket)就是通过这种方式来处理websocket断网重连。
当然这么好用的websocket也不是没有它的问题,websocket目前来看最大的问题是浏览器的支持(幸好大部分的服务器软件在比较新的版本中都已经支持了websocket),ie直到10才开始支持这种协议,而且每个浏览器最近在升级浏览器的时候,都会对websocket做出细微的调整。而且,想象你打开一个页面,当这个页面打开websocket连接并且执行一个内部IP地址的端口扫描,如果端口扫描发现了内部网络上发现了一个开启的80端口,一个隧道就可能通过你的浏览器建立。这样做很可能最终绕过防火墙,并且允许访问内部内容。所以安全问题,也是websocket现在面临的一大隐患。
WebSocket是HTML5出的协议,也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)。
首先HTTP有 1.1 和 1.0 之说,也就是所谓的 keep-alive ,把多个HTTP请求合并为一个,但是 Websocket 其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充。有交集,但是并不是全部。
另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。通俗来说,你可以用HTTP协议传输非Html数据,就是这样。再简单来说,层级不一样。
WebSocket的协议是持久化的,而HTTP是非持久化的协议。
今天说到这里,关于WebSocket的下次我们接着聊。www.goeasy.io 这家是专门做WebSocket的,有兴趣可以关注一下。

实力解决微信支付问题~
关于微信支付的时候,一直提示-1的问题,我也是整理了半天,才弄出来个原因,
首先,准备工作要做好,要保证:
1、menifest.json中配置了微信的appid
2、服务端请求prepareid正确返回;
3、服务端返回数据格式与官方一致:
4、android版云打包,数字签名,与微信开放平台配置一致(不会的用百度);
这四个要保证
一、确保APP端代码没有问题
先保证用官方的基座然后模拟器测试,可以正常调起微信支付,这一点是为了保证APP里面的代码是正常的,
因为微信支付不能真机调试,而且我用自定义基座也不能正常更新,不知道是不是BUG
官方文档:支付插件配置
注意:此文章里面,官方中微信接口的链接改成这个:http://demo.dcloud.net.cn/payment/wxpayv3.HBuilder/?total=
二、将APP端请求的代码改成自己的
如果你是用上面的文档的代码的话,将WXPAYSERVER的值改成自己的服务器接口链接,然后自己证书打包安装在手机上
然后就是处理服务器端就可以了,此时安利几个工具:Fiddler(抓包)、PostMan(模拟请求)以及一款可以内网穿透的工具(如Ngrok)
有了上面三个工具,可以开心愉快的测试了
三、服务器端处理
我用的是TP5,但是其他的也一样,使用的是微信的SDK;
这一点,咱官方也是有一个github文档微信支付示例
关于这一点,如果你只按上面的文档来的话,你不会成功的,因为微信支付有两个点:1、先生成prepareid(预订单),2、根据prepareid再进行一次签名才可以返回给app!
1、生成预订单:
使用微信的SDK,要在config中配置四个参数:APPID、MCHID、KEY、APPSECRET,四个参数是什么意思在SDK中有,注意,key这个参数在下面也要使用到
我的是这样的:
$wxOrderData = new \WxPayUnifiedOrder();
$wxOrderData->SetOut_trade_no($this->orderNo); //这个换成自己的订单号
$wxOrderData->SetTrade_type('APP');//这个参数是固定的,必须是APP
$wxOrderData->SetTotal_fee($orderPrice * 100); //这个是支付金额(单位是分)
$wxOrderData->SetBody('XXX商城'); //这个自己随意
$wxOrderData->SetNotify_url( $backUrl ); //这个回调,这个地址也是你自己的
$result = \WxPayApi::unifiedOrder($wxOrderData); //此时$result就是返回的prepareid的信息
// 请先确保这里请求成功,成功的话是预订单这个$result ['prepay_id'],然后调用$this->sign($result ['prepay_id']);,返回的数组就是要向app返回的信息
2、生成签名并返回详细信息
之前做过小程序支付,也有这一步,于是就将小程序的代码复制过来了,结果失败,就一直没找到原因,直到我看到微信APP开发文档的时候,有这么一句话:不好意思,刚才去找了一下,,,,找不到了,反正就是签名是由五个参数生成的:timestamp、appid、partnerid、prepayid、noncestr、package,这五个少一个都不行!
private function sign($prepayid) //$prepayid这个参数就是第1步里面获取的预订单id
{
$time = (string)time();
$rand = md5(time() . mt_rand(0, 1000));
$data = [];
$data['timestamp'] = $time;
$data['appid'] = '这是你的appid';
$data['partnerid'] = '这是你的商户号';
$data['prepayid'] = $prepayid;
$data['noncestr'] = $rand;
$data['package'] = 'Sign=WXPay'; //介个是固定的
$sign = $this->MakeSign( $data );
$data['sign'] = $sign;
return $data; //这个数组就是返回给app的信息
}
private function ToUrlParams($data)
{
$buff = "";
foreach ($data as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
private function MakeSign( $data )
{
//签名步骤一:按字典序排序参数
ksort($data);
$string = $this->ToUrlParams($data);
//签名步骤二:在string后加入KEY
$string = $string . "&key=你的key"; //注意,敲黑板了,这里还要加上在config中配置过的key
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
四、对比官方返回的参数,官方返回的参数是下面这样的:
{
"appid": "wx0411fa6a39d61297",
"noncestr": "9p5hdwtt0jsoYw22",
"package": "Sign=WXPay",
"partnerid": "1230636401",
"prepayid": "wx121809269549694a9dde5a333322923488",
"timestamp": 1534068566,
"sign": "19174B7A2EE5463007FFFF8298F4538E"
}
可以将自己的返回信息和上面的进行对比,发现是一样的,都是7个参数,且参数都一样
注:有的时候,第一次拉取成功了,但是并没有支付而是返回了,然后再拉取的时候会报错,因为订单号重复了,这时候有抓包的工具的话,是可以看到prepayid是null,因为预订单是有时效的,这个需要自己在做一下判断。
还有一个注意点:plus.payment.request发起支付的时候,接收到的参数是json格式的字符串而不是对象,这点要注意一下,因为我封装了ajax请求,默认将json格式转为对象,所以在用的时候要将参数再转为字符串
以上是我自己的经验,有啥问题大家都可以分享一下。
关于微信支付的时候,一直提示-1的问题,我也是整理了半天,才弄出来个原因,
首先,准备工作要做好,要保证:
1、menifest.json中配置了微信的appid
2、服务端请求prepareid正确返回;
3、服务端返回数据格式与官方一致:
4、android版云打包,数字签名,与微信开放平台配置一致(不会的用百度);
这四个要保证
一、确保APP端代码没有问题
先保证用官方的基座然后模拟器测试,可以正常调起微信支付,这一点是为了保证APP里面的代码是正常的,
因为微信支付不能真机调试,而且我用自定义基座也不能正常更新,不知道是不是BUG
官方文档:支付插件配置
注意:此文章里面,官方中微信接口的链接改成这个:http://demo.dcloud.net.cn/payment/wxpayv3.HBuilder/?total=
二、将APP端请求的代码改成自己的
如果你是用上面的文档的代码的话,将WXPAYSERVER的值改成自己的服务器接口链接,然后自己证书打包安装在手机上
然后就是处理服务器端就可以了,此时安利几个工具:Fiddler(抓包)、PostMan(模拟请求)以及一款可以内网穿透的工具(如Ngrok)
有了上面三个工具,可以开心愉快的测试了
三、服务器端处理
我用的是TP5,但是其他的也一样,使用的是微信的SDK;
这一点,咱官方也是有一个github文档微信支付示例
关于这一点,如果你只按上面的文档来的话,你不会成功的,因为微信支付有两个点:1、先生成prepareid(预订单),2、根据prepareid再进行一次签名才可以返回给app!
1、生成预订单:
使用微信的SDK,要在config中配置四个参数:APPID、MCHID、KEY、APPSECRET,四个参数是什么意思在SDK中有,注意,key这个参数在下面也要使用到
我的是这样的:
$wxOrderData = new \WxPayUnifiedOrder();
$wxOrderData->SetOut_trade_no($this->orderNo); //这个换成自己的订单号
$wxOrderData->SetTrade_type('APP');//这个参数是固定的,必须是APP
$wxOrderData->SetTotal_fee($orderPrice * 100); //这个是支付金额(单位是分)
$wxOrderData->SetBody('XXX商城'); //这个自己随意
$wxOrderData->SetNotify_url( $backUrl ); //这个回调,这个地址也是你自己的
$result = \WxPayApi::unifiedOrder($wxOrderData); //此时$result就是返回的prepareid的信息
// 请先确保这里请求成功,成功的话是预订单这个$result ['prepay_id'],然后调用$this->sign($result ['prepay_id']);,返回的数组就是要向app返回的信息
2、生成签名并返回详细信息
之前做过小程序支付,也有这一步,于是就将小程序的代码复制过来了,结果失败,就一直没找到原因,直到我看到微信APP开发文档的时候,有这么一句话:不好意思,刚才去找了一下,,,,找不到了,反正就是签名是由五个参数生成的:timestamp、appid、partnerid、prepayid、noncestr、package,这五个少一个都不行!
private function sign($prepayid) //$prepayid这个参数就是第1步里面获取的预订单id
{
$time = (string)time();
$rand = md5(time() . mt_rand(0, 1000));
$data = [];
$data['timestamp'] = $time;
$data['appid'] = '这是你的appid';
$data['partnerid'] = '这是你的商户号';
$data['prepayid'] = $prepayid;
$data['noncestr'] = $rand;
$data['package'] = 'Sign=WXPay'; //介个是固定的
$sign = $this->MakeSign( $data );
$data['sign'] = $sign;
return $data; //这个数组就是返回给app的信息
}
private function ToUrlParams($data)
{
$buff = "";
foreach ($data as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
private function MakeSign( $data )
{
//签名步骤一:按字典序排序参数
ksort($data);
$string = $this->ToUrlParams($data);
//签名步骤二:在string后加入KEY
$string = $string . "&key=你的key"; //注意,敲黑板了,这里还要加上在config中配置过的key
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
四、对比官方返回的参数,官方返回的参数是下面这样的:
{
"appid": "wx0411fa6a39d61297",
"noncestr": "9p5hdwtt0jsoYw22",
"package": "Sign=WXPay",
"partnerid": "1230636401",
"prepayid": "wx121809269549694a9dde5a333322923488",
"timestamp": 1534068566,
"sign": "19174B7A2EE5463007FFFF8298F4538E"
}
可以将自己的返回信息和上面的进行对比,发现是一样的,都是7个参数,且参数都一样
注:有的时候,第一次拉取成功了,但是并没有支付而是返回了,然后再拉取的时候会报错,因为订单号重复了,这时候有抓包的工具的话,是可以看到prepayid是null,因为预订单是有时效的,这个需要自己在做一下判断。
还有一个注意点:plus.payment.request发起支付的时候,接收到的参数是json格式的字符串而不是对象,这点要注意一下,因为我封装了ajax请求,默认将json格式转为对象,所以在用的时候要将参数再转为字符串
以上是我自己的经验,有啥问题大家都可以分享一下。
收起阅读 »
PHP编程之收入支出明细表实现技术
账户金额明细表是统计用户所花的每笔金额和用户所在这个系统所赚的每笔金额,通俗的讲也就是收入和支出。但是很多编程技术人员在刚开始的时候,不知道如何去实现,往往或出现有收入记录却无支出记录,或者是相反的情况,所以对于这个问题,下面专业的郑州app开发公司燚轩科技就来为大家分析讲解一下。
1、客户所在本系统消费的金额所产生的提成,写入本记录表中。php代码如下:
if(I('pay_state')==2 && I('state')==3){
$money=$info['money']/100;
$uid=$info['uid'];
$update['authe_uid']=$info['uid'];
$user=M('user');
$list=$user->where("uid=$uid")->find();
$sale_uid=$list['sale_uid'];
$update['sale_uid']=$list['sale_uid'];
$bili=M('sys')->where("id=1")->find();
$bi=$bili['sale_rate']/100;
$put_money=$money$bi/100;
$update['money']=$put_money100;
$update['real_money']=$put_money100;
$update['time']=time();
$update['state']=1;
$update['type']=2;
$sale_user=M('sale_user');
$sale=$sale_user->where("sale_uid=$sale_uid")->find();
$up['tal_money']=$sale['tal_money']+$put_money100;
$sale_user->where("sale_uid=$sale_uid")->save($up); }
2、平台给销售代理定时发放的金额,写入本记录表中。php代码如下:
public function dopay_money(){
if(I("bank_card")==''){
error("打款账号不能为空");die;
}
if(I("money_num")==''){
error("打款单号不能为空");die;
}
if(I("money")==''){
error("打款金额不能为空");die;
}
if(I("money")>I("tal_money")){
error("账户总金额不足");die;
}
$bank_card=I("bank_card");
$money_num=I("money_num");
$money=I("money");
$sale_uid=I("sale_uid");
$info=M("sys")->where("id=1")->find();
$min_money=$info['min_money']/100;
if($money<$min_money){
error("打款金额最低为".$min_money."元");
}
$sale_user=M("sale_user");
$moneyb=M("money");
$userinfo=$sale_user->where("sale_uid=$sale_uid")->find();
$data['tal_money']=$userinfo['tal_money']-$money*100;
if($sale_user->where("sale_uid=$sale_uid")->save($data)){
$da['sale_uid']=$sale_uid;
$da['money']=$money*100;
$da['real_money']=$money*100;
$da['time']=time();
$da['state']=2;
$da['type']=1;
$da['bank_card']=$bank_card;
$da['money_num']=$money_num;
if($moneyb->add($da)){
success("成功",U("Oasys/sale"));
}else{
error("失败");
}
}
}
好了,看到这里相信大家都知道该如何去做了,那么如果大家还是存在一些细节问题的话,可以留言咨询,我们看到后会第一时间回复。本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处。
账户金额明细表是统计用户所花的每笔金额和用户所在这个系统所赚的每笔金额,通俗的讲也就是收入和支出。但是很多编程技术人员在刚开始的时候,不知道如何去实现,往往或出现有收入记录却无支出记录,或者是相反的情况,所以对于这个问题,下面专业的郑州app开发公司燚轩科技就来为大家分析讲解一下。
1、客户所在本系统消费的金额所产生的提成,写入本记录表中。php代码如下:
if(I('pay_state')==2 && I('state')==3){
$money=$info['money']/100;
$uid=$info['uid'];
$update['authe_uid']=$info['uid'];
$user=M('user');
$list=$user->where("uid=$uid")->find();
$sale_uid=$list['sale_uid'];
$update['sale_uid']=$list['sale_uid'];
$bili=M('sys')->where("id=1")->find();
$bi=$bili['sale_rate']/100;
$put_money=$money$bi/100;
$update['money']=$put_money100;
$update['real_money']=$put_money100;
$update['time']=time();
$update['state']=1;
$update['type']=2;
$sale_user=M('sale_user');
$sale=$sale_user->where("sale_uid=$sale_uid")->find();
$up['tal_money']=$sale['tal_money']+$put_money100;
$sale_user->where("sale_uid=$sale_uid")->save($up); }
2、平台给销售代理定时发放的金额,写入本记录表中。php代码如下:
public function dopay_money(){
if(I("bank_card")==''){
error("打款账号不能为空");die;
}
if(I("money_num")==''){
error("打款单号不能为空");die;
}
if(I("money")==''){
error("打款金额不能为空");die;
}
if(I("money")>I("tal_money")){
error("账户总金额不足");die;
}
$bank_card=I("bank_card");
$money_num=I("money_num");
$money=I("money");
$sale_uid=I("sale_uid");
$info=M("sys")->where("id=1")->find();
$min_money=$info['min_money']/100;
if($money<$min_money){
error("打款金额最低为".$min_money."元");
}
$sale_user=M("sale_user");
$moneyb=M("money");
$userinfo=$sale_user->where("sale_uid=$sale_uid")->find();
$data['tal_money']=$userinfo['tal_money']-$money*100;
if($sale_user->where("sale_uid=$sale_uid")->save($data)){
$da['sale_uid']=$sale_uid;
$da['money']=$money*100;
$da['real_money']=$money*100;
$da['time']=time();
$da['state']=2;
$da['type']=1;
$da['bank_card']=$bank_card;
$da['money_num']=$money_num;
if($moneyb->add($da)){
success("成功",U("Oasys/sale"));
}else{
error("失败");
}
}
}
好了,看到这里相信大家都知道该如何去做了,那么如果大家还是存在一些细节问题的话,可以留言咨询,我们看到后会第一时间回复。本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处。

uni-app 跨平台应用开发教程已经发布
uni-app 跨平台应用开发教程已经发布
一套代码可以发布为ios Android app、小程序。
课程总计25节 + 补充课程覆盖了开发中常用的知识点,知识点覆盖率 90% 以上!
通过课程您将学会:
1、uni-app
2、小程序
3、vue 基础
课程购买地址
https://ke.qq.com/course/323825?tuin=4f8da6
uni-app 跨平台应用开发教程已经发布
一套代码可以发布为ios Android app、小程序。
课程总计25节 + 补充课程覆盖了开发中常用的知识点,知识点覆盖率 90% 以上!
通过课程您将学会:
1、uni-app
2、小程序
3、vue 基础
课程购买地址
https://ke.qq.com/course/323825?tuin=4f8da6

为UNIAPP项目添加less、scss、stylus支持
文章内容已过期,最新版HBuilderX在处理less、scss、stylus时无需如此复杂。HBuilderX插件管理里安装less等编译插件后可直接使用。
但以下内容对typescript、coffeescript、pug仍然有效,使用下面的方式更换对应loader。
有个注意,uni-app插件目录会随着uni-app插件的升级而被替换。
==============分割线==============
-
找到HBuilderX安装目录下的 plugins\uniapp 目录
-
在该目录下的命令行窗口执行 npm install less less-loader --save(可使用cnpm)安装加载器
-
打开plugins\uniapp\build\webpack.base.conf.js 文件,添加
{ test: /\.less$/, loader: "style-loader!css-loader!less-loader", }
到module.rules下。
-
然后就可以在vue文件中使用less编写css了,例:
<style lang="less">
@import "../../static/css/tools.less";
</style>
文章内容已过期,最新版HBuilderX在处理less、scss、stylus时无需如此复杂。HBuilderX插件管理里安装less等编译插件后可直接使用。
但以下内容对typescript、coffeescript、pug仍然有效,使用下面的方式更换对应loader。
有个注意,uni-app插件目录会随着uni-app插件的升级而被替换。
==============分割线==============
-
找到HBuilderX安装目录下的 plugins\uniapp 目录
-
在该目录下的命令行窗口执行 npm install less less-loader --save(可使用cnpm)安装加载器
-
打开plugins\uniapp\build\webpack.base.conf.js 文件,添加
{ test: /\.less$/, loader: "style-loader!css-loader!less-loader", }
到module.rules下。
-
然后就可以在vue文件中使用less编写css了,例:
<style lang="less">
@import "../../static/css/tools.less";
</style>

建议把蓝牙这一块完善下。特别是BLE低功耗蓝牙
现在只能设备越来越多,好多app都需要和蓝牙打交道,如果能把蓝牙这一块完善一下的话就好了。特别是针对低功耗蓝牙的的支持。
现在只能设备越来越多,好多app都需要和蓝牙打交道,如果能把蓝牙这一块完善一下的话就好了。特别是针对低功耗蓝牙的的支持。