
可恶!老年手机里植入木马程序 非法获利6600余万元
近日,攀枝花市公安局东区分局成功破获一起非法控制计算机信息系统案件,打掉了三个控制“老年”手机非法获利的犯罪团伙。

去年3月,攀枝花市公安局东区分局接到一条线索,称一名75岁退休老人收到一条诈骗短信,被以刷单的方式诈骗资金6400元,然而这位老人他使用是一款老年手机。
民警发现该手机号向200余个手机发送了380条短信。通过调查发现该手机被植入了控制手机的木马程序,被外部服务器控制向他人发送诈骗短信。发送诈骗短信的电话是攀枝花市东区一居民孙某。经过进一步侦查工作,发现该团伙是以陈某某为首的犯罪团伙,他们在深圳注册了专门的科技公司生产手机,将植入木马功能的老年机销向市场,进行非法控制获取非法利益。该手机一旦被人购买插卡使用,便会主动将手机号码发送给犯罪团伙,并自动与科技公司的后台服务器发生联网,达到控制目标手机的目的。
随后专案组兵分三路,分别前往深圳、浙江、重庆开展收网工作,抓获了涉案人员25人,并起获了大量的后台服务器数据和尚未出售的装有木马的手机2万余部。随后调取后台服务数据显示,涉及受害手机达600余万部,涉案金额达4亿元。受害者遍及全国31个省、直辖市、自治区,犯罪团伙非法获利6600余万元。
民警提醒:部分非正规厂家生产的老年机可能存在被植入木马的隐患,因此我们在购买老年机的时候要选择正规厂商正规的品牌购买,一旦发现自己的资费有问题的时候,要去运营商查看相关情况,以防被不法分子利用。
此文章【来源:四川观察】,转载自【腾讯网】,如有不当联系邮箱:pufa@dcloud.io 删除。原文链接
版权归原作者所有,向原创致敬。
近日,攀枝花市公安局东区分局成功破获一起非法控制计算机信息系统案件,打掉了三个控制“老年”手机非法获利的犯罪团伙。
去年3月,攀枝花市公安局东区分局接到一条线索,称一名75岁退休老人收到一条诈骗短信,被以刷单的方式诈骗资金6400元,然而这位老人他使用是一款老年手机。
民警发现该手机号向200余个手机发送了380条短信。通过调查发现该手机被植入了控制手机的木马程序,被外部服务器控制向他人发送诈骗短信。发送诈骗短信的电话是攀枝花市东区一居民孙某。经过进一步侦查工作,发现该团伙是以陈某某为首的犯罪团伙,他们在深圳注册了专门的科技公司生产手机,将植入木马功能的老年机销向市场,进行非法控制获取非法利益。该手机一旦被人购买插卡使用,便会主动将手机号码发送给犯罪团伙,并自动与科技公司的后台服务器发生联网,达到控制目标手机的目的。
随后专案组兵分三路,分别前往深圳、浙江、重庆开展收网工作,抓获了涉案人员25人,并起获了大量的后台服务器数据和尚未出售的装有木马的手机2万余部。随后调取后台服务数据显示,涉及受害手机达600余万部,涉案金额达4亿元。受害者遍及全国31个省、直辖市、自治区,犯罪团伙非法获利6600余万元。
民警提醒:部分非正规厂家生产的老年机可能存在被植入木马的隐患,因此我们在购买老年机的时候要选择正规厂商正规的品牌购买,一旦发现自己的资费有问题的时候,要去运营商查看相关情况,以防被不法分子利用。
此文章【来源:四川观察】,转载自【腾讯网】,如有不当联系邮箱:pufa@dcloud.io 删除。原文链接
版权归原作者所有,向原创致敬。

编写微信小程序报渲染层错误[1]
问题:在编写微信小程序用到组件调用时,在子组件内部将props中的属性值动态赋给data中的某个状态值时,报 渲染层错误” Expect END descriptor with depth 1 but get another,
原因:我在组件created生命函数中直接赋的值,在网上查的资料说是微信小程序中不能这样修改数据,得用seData()函数修改。后来定义了个方法,在方法中实现动态赋值,然后在生命函数中调用这个方法就行了
问题:在编写微信小程序用到组件调用时,在子组件内部将props中的属性值动态赋给data中的某个状态值时,报 渲染层错误” Expect END descriptor with depth 1 but get another,
原因:我在组件created生命函数中直接赋的值,在网上查的资料说是微信小程序中不能这样修改数据,得用seData()函数修改。后来定义了个方法,在方法中实现动态赋值,然后在生命函数中调用这个方法就行了

uni-app mDNS
// #ifdef APP-PLUS
let vm = this;
let mServerType = '_http._tcp.'; //服务类型
let NsdServiceInfo = plus.android.importClass('android.net.nsd.NsdServiceInfo');
let NsdManager = plus.android.importClass('android.net.nsd.NsdManager');
let Context = plus.android.importClass('android.content.Context');
// 导入后可以使用new方法创建类的实例对象
let nsd_service_info = new NsdServiceInfo();
let nsd_manager = new NsdManager();
//获取应用主Activity实例对象系统服务NSD_SERVICE方法
let mNsdManager = plus.android.runtimeMainActivity().getSystemService(Context.NSD_SERVICE);
//实列API接口监听回调函数
let mDiscoveryListener = plus.android.implements('android.net.nsd.NsdManager$DiscoveryListener', {
onServiceFound: function(service) {
//先发现设备服务再执行连接获取数据
//导入service类
plus.android.importClass(service);
//实列化连接服务接口监听回调函数
//注意NsdManager$ResolveListener中间使用$不是“.”
let mResolveListener = plus.android.implements('android.net.nsd.NsdManager$ResolveListener', {
onServiceResolved: function(services) {
//连接服务
let name = services.getServiceName();
let port = services.getPort();
let ip = services.getHost();
plus.android.importClass(ip); //导入services.getHost()类
ip = ip.getHostAddress();
let arry = {
name: name,
port: port,
ip: ip
};
console.log(arry)
if(name == "esp8266"){
mNsdManager.stopServiceDiscovery(mResolveListener);
}
}
});
mNsdManager.resolveService(service, mResolveListener); //启动连接服务
}
});
// 导入mNsdManager Java类对象
plus.android.importClass(mNsdManager);
mNsdManager.discoverServices(mServerType, 1, mDiscoveryListener); //启动监听服务(类型,常量,回调函数)参考java discoverServices需要携带的参数类型
// #endif
// #ifdef APP-PLUS
let vm = this;
let mServerType = '_http._tcp.'; //服务类型
let NsdServiceInfo = plus.android.importClass('android.net.nsd.NsdServiceInfo');
let NsdManager = plus.android.importClass('android.net.nsd.NsdManager');
let Context = plus.android.importClass('android.content.Context');
// 导入后可以使用new方法创建类的实例对象
let nsd_service_info = new NsdServiceInfo();
let nsd_manager = new NsdManager();
//获取应用主Activity实例对象系统服务NSD_SERVICE方法
let mNsdManager = plus.android.runtimeMainActivity().getSystemService(Context.NSD_SERVICE);
//实列API接口监听回调函数
let mDiscoveryListener = plus.android.implements('android.net.nsd.NsdManager$DiscoveryListener', {
onServiceFound: function(service) {
//先发现设备服务再执行连接获取数据
//导入service类
plus.android.importClass(service);
//实列化连接服务接口监听回调函数
//注意NsdManager$ResolveListener中间使用$不是“.”
let mResolveListener = plus.android.implements('android.net.nsd.NsdManager$ResolveListener', {
onServiceResolved: function(services) {
//连接服务
let name = services.getServiceName();
let port = services.getPort();
let ip = services.getHost();
plus.android.importClass(ip); //导入services.getHost()类
ip = ip.getHostAddress();
let arry = {
name: name,
port: port,
ip: ip
};
console.log(arry)
if(name == "esp8266"){
mNsdManager.stopServiceDiscovery(mResolveListener);
}
}
});
mNsdManager.resolveService(service, mResolveListener); //启动连接服务
}
});
// 导入mNsdManager Java类对象
plus.android.importClass(mNsdManager);
mNsdManager.discoverServices(mServerType, 1, mDiscoveryListener); //启动监听服务(类型,常量,回调函数)参考java discoverServices需要携带的参数类型
// #endif
收起阅读 »

unipush服务端推送PHP版RestAPI V2 的离线/在线推送
关于unipush的推送还是用个推的文档和SDK,下载个推的SDK整合进PHP框架里,然后开始表演了。刚开始在网上找真的都是老版本的,RestAPI V2 的几乎没有涉及,旧SDK的可能以后都要不支持了,所以建议大家更换新版本的SDK。话不多说,上代码:
$title为推送标题,$content为推送内容,$payload为点击通知加自定义消息,$cid为推送cid,$package为APP包名,"APPKEY","APPID","MasterSecret"这几个要传入你真实的。以下是单推例子,更多推送就不多说了。
function pushToSingleByCid($title,$content,$payload,$cid,$package){
//创建API,APPID等配置参考 环境要求 进行获取
$api = new \GTClient_unipush("https://restapi.getui.com","APPKEY","APPID","MasterSecret");
//设置推送参数
$push = new \GTPushRequest();
$osn = date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
$push->setRequestId((string)$osn);
$message = new \GTPushMessage();
$channel = new \GTPushChannel();
$notify = new \GTNotification();
$thirdnotify = new \GTThirdNotification();
$ups = new \GTUps();
$gtAndroid = new \GTAndroid();
$notify->setTitle($title);
$notify->setBody($content);
$thirdnotify->setTitle($title);
$thirdnotify->setBody($content);
if(is_array($payload))
$pj = json_encode($payload);
else
$pj = $payload;
$notify-> setPayload($pj);
$thirdnotify-> setPayload($pj);
$intent = "intent:#Intent;launchFlags=0x14000000;action=android.intent.action.oppopush;component={$package}/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title={$title};S.content={$content};S.payload={$pj};end";
$notify->setClickType("intent");
$thirdnotify->setClickType("intent");
$notify->setIntent($intent);
$thirdnotify->setIntent($intent);
echo $intent;
//点击通知后续动作,目前支持以下后续动作:
//1、intent:打开应用内特定页面url:打开网页地址。2、payload:自定义消息内容启动应用。3、payload_custom:自定义消息内容不启动应用。4、startapp:打开应用首页。5、none:纯通知,无后续动作
$notify->setIntent($intent);
// $notify->setChannelLevel(3);
// $touchuan=['title'=>$title,'content'=>$content,'payload'=>$package];
//$message->setTransmission(json_encode($touchuan));//个推透传
$message->setNotification($notify);
$upsback= $ups->setNotification($thirdnotify);
// $upsback= $ups->setTransmission(json_encode($touchuan));//厂商透传
$gtAndroid->setUps($ups);
$channel->setAndroid($gtAndroid);
$push->setPushMessage($message);
$push->setPushChannel( $channel);
$push->setCid($cid);
//处理返回结果
$result = $api->pushApi()->pushToSingleByCid($push);
// print_r($result);
}
关于unipush的推送还是用个推的文档和SDK,下载个推的SDK整合进PHP框架里,然后开始表演了。刚开始在网上找真的都是老版本的,RestAPI V2 的几乎没有涉及,旧SDK的可能以后都要不支持了,所以建议大家更换新版本的SDK。话不多说,上代码:
$title为推送标题,$content为推送内容,$payload为点击通知加自定义消息,$cid为推送cid,$package为APP包名,"APPKEY","APPID","MasterSecret"这几个要传入你真实的。以下是单推例子,更多推送就不多说了。
function pushToSingleByCid($title,$content,$payload,$cid,$package){
//创建API,APPID等配置参考 环境要求 进行获取
$api = new \GTClient_unipush("https://restapi.getui.com","APPKEY","APPID","MasterSecret");
//设置推送参数
$push = new \GTPushRequest();
$osn = date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
$push->setRequestId((string)$osn);
$message = new \GTPushMessage();
$channel = new \GTPushChannel();
$notify = new \GTNotification();
$thirdnotify = new \GTThirdNotification();
$ups = new \GTUps();
$gtAndroid = new \GTAndroid();
$notify->setTitle($title);
$notify->setBody($content);
$thirdnotify->setTitle($title);
$thirdnotify->setBody($content);
if(is_array($payload))
$pj = json_encode($payload);
else
$pj = $payload;
$notify-> setPayload($pj);
$thirdnotify-> setPayload($pj);
$intent = "intent:#Intent;launchFlags=0x14000000;action=android.intent.action.oppopush;component={$package}/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title={$title};S.content={$content};S.payload={$pj};end";
$notify->setClickType("intent");
$thirdnotify->setClickType("intent");
$notify->setIntent($intent);
$thirdnotify->setIntent($intent);
echo $intent;
//点击通知后续动作,目前支持以下后续动作:
//1、intent:打开应用内特定页面url:打开网页地址。2、payload:自定义消息内容启动应用。3、payload_custom:自定义消息内容不启动应用。4、startapp:打开应用首页。5、none:纯通知,无后续动作
$notify->setIntent($intent);
// $notify->setChannelLevel(3);
// $touchuan=['title'=>$title,'content'=>$content,'payload'=>$package];
//$message->setTransmission(json_encode($touchuan));//个推透传
$message->setNotification($notify);
$upsback= $ups->setNotification($thirdnotify);
// $upsback= $ups->setTransmission(json_encode($touchuan));//厂商透传
$gtAndroid->setUps($ups);
$channel->setAndroid($gtAndroid);
$push->setPushMessage($message);
$push->setPushChannel( $channel);
$push->setCid($cid);
//处理返回结果
$result = $api->pushApi()->pushToSingleByCid($push);
// print_r($result);
}
收起阅读 »

基于uniapp+yii2的全套OA办公系统,提供前后端源码,支持多端部署
简介
UNI办公系统主要为国内企业提供办公自动化信息服务,功能如:工作流、工作审批(报修申请、报销申请、领用申请、申购申请、请假申请、出差申请、加班申请、用工申请、接待申请、用车申请);个人中心(公告管理、消息管理、工作日志、我的日程、工作总结);知识管理(新闻动态、管理制度、下载中心等);日常管理(资产管理、车辆管理、档案管理、考勤管理、巡更巡检、合同管理、后勤采购、就餐统计、通讯录);人事管理(员工信息、奖惩管理、社保管理等)、考勤管理(班次管理、排班管理、我的排班、签到签退);巡更巡检(地点管理、巡更班次、巡更计划、我的排班、巡更记录);意见反馈、站点帮助、在线客服、一键换肤等功能模块。
系统前端基于uniapp开发,后端基于php开发;该系统可独立部署在自己的服务器,且支持单企业版和多企业版本;可后台根据用户角色权限控制手机端功能模块的显示;目前已适配H5、微信小程序、安卓和ios,如果在试用或购买后发现问题,欢迎您随时提出。
咨询
作者QQ:21931118 QQ群:1107210028
如您已下载本插件,可加入QQ群一起讨论,作者不承诺技术支持;
演示
- 后台演示账号:后台不开源,不免费提供后台账号及接口
- 手机端测试版:测试版自己加群下载,账密:18986860001/18986860001(请扫码H5或者安卓,苹果和小程序版不提供测试账号)
- 业务合作:加Q私聊
- 官方网站:unioa插件市场
手机端部分截图
后台部分截图
安装插件
已安装插件
工作流列表
工作流配置
流程状态
配置审核人员
支持指定人员审核和指定角色审核
工作流转
新增流程节点
待办工作
已办工作
如果审核失误,在下一级没有审核的情况下,可点击重审按钮进行重新审核,流程将重新转入申请状态。
审核工作
创建申请
查看进度
如果工作已有人员进行审核,进入工作流转后,用户不能编辑和删除该工作。
企业管理人员可自定义工作类型
班次管理
排班管理
我的排班
签到列表
新建打卡
插件市场 总有一款插件适合你!
开始使用
- 将项目导入HBuildX
- 修改配置文件config/index.conf.js内配置对应参数
- 运行即可体验
发行微信小程序
在HBuildx顶部菜单点击运行->运行到微信小程序
使用微信开发者工具上传版本并审核通过即可
注意:小程序需额外配置服务器域名
发行H5
在HBuildx顶部菜单点击发行->网站-H5手机版
在弹出的对话框中输入网站标题和域名即可,将编译后的资源部署到服务器(虚拟主机)
需注意HBx直接部署网页托管需要最新版,老版本没有这个选项,可以自己到web控制台进行托管。
点击发行,等待项目编译部署即可。
如果您不想购买服务器,那就来uniCloud白嫖一波吧~
发行ios版和安卓版
在HBuildx顶部菜单点击发行->原生App-云打包,
在弹出的对话框中选择证书文件和输入密码即可。
隐私、权限声明
-
本插件需要申请的系统权限列表:
1.定位权限 2.拍照权限 3.相册权限
-
本插件采集的数据、发送的服务器地址、以及数据用途说明:
无
-
本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:
无
简介
UNI办公系统主要为国内企业提供办公自动化信息服务,功能如:工作流、工作审批(报修申请、报销申请、领用申请、申购申请、请假申请、出差申请、加班申请、用工申请、接待申请、用车申请);个人中心(公告管理、消息管理、工作日志、我的日程、工作总结);知识管理(新闻动态、管理制度、下载中心等);日常管理(资产管理、车辆管理、档案管理、考勤管理、巡更巡检、合同管理、后勤采购、就餐统计、通讯录);人事管理(员工信息、奖惩管理、社保管理等)、考勤管理(班次管理、排班管理、我的排班、签到签退);巡更巡检(地点管理、巡更班次、巡更计划、我的排班、巡更记录);意见反馈、站点帮助、在线客服、一键换肤等功能模块。
系统前端基于uniapp开发,后端基于php开发;该系统可独立部署在自己的服务器,且支持单企业版和多企业版本;可后台根据用户角色权限控制手机端功能模块的显示;目前已适配H5、微信小程序、安卓和ios,如果在试用或购买后发现问题,欢迎您随时提出。
咨询
作者QQ:21931118 QQ群:1107210028
如您已下载本插件,可加入QQ群一起讨论,作者不承诺技术支持;
演示
- 后台演示账号:后台不开源,不免费提供后台账号及接口
- 手机端测试版:测试版自己加群下载,账密:18986860001/18986860001(请扫码H5或者安卓,苹果和小程序版不提供测试账号)
- 业务合作:加Q私聊
- 官方网站:unioa插件市场
手机端部分截图
后台部分截图
安装插件
已安装插件
工作流列表
工作流配置
流程状态
配置审核人员
支持指定人员审核和指定角色审核
工作流转
新增流程节点
待办工作
已办工作
如果审核失误,在下一级没有审核的情况下,可点击重审按钮进行重新审核,流程将重新转入申请状态。
审核工作
创建申请
查看进度
如果工作已有人员进行审核,进入工作流转后,用户不能编辑和删除该工作。
企业管理人员可自定义工作类型
班次管理
排班管理
我的排班
签到列表
新建打卡
插件市场 总有一款插件适合你!
开始使用
- 将项目导入HBuildX
- 修改配置文件config/index.conf.js内配置对应参数
- 运行即可体验
发行微信小程序
在HBuildx顶部菜单点击运行->运行到微信小程序
使用微信开发者工具上传版本并审核通过即可
注意:小程序需额外配置服务器域名
发行H5
在HBuildx顶部菜单点击发行->网站-H5手机版
在弹出的对话框中输入网站标题和域名即可,将编译后的资源部署到服务器(虚拟主机)
需注意HBx直接部署网页托管需要最新版,老版本没有这个选项,可以自己到web控制台进行托管。
点击发行,等待项目编译部署即可。
如果您不想购买服务器,那就来uniCloud白嫖一波吧~
发行ios版和安卓版
在HBuildx顶部菜单点击发行->原生App-云打包,
在弹出的对话框中选择证书文件和输入密码即可。
隐私、权限声明
-
本插件需要申请的系统权限列表:
1.定位权限 2.拍照权限 3.相册权限
-
本插件采集的数据、发送的服务器地址、以及数据用途说明:
无
-
本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:
无

个人发卡网源码内核
发卡网源码演示及下载地址:fakaysw.top
<?php
namespace app\admin\controller;
use controller\BasicAdmin;
use think\Db;
class App extends BasicAdmin
{
public function index()
{
if (!$this->request->isPost()) {
return $this->fetch();
}
$version = input('version/s');
if(empty($version)){
$this->error('请输入版本号');
}
$data = [
'platform' => input('platform/s'),
'version' => $version,
];
//判断是否已经存在相同的版本号
$res = Db::name('app_version')->where($data)->find();
if($res){
$this->error('已存在相同版本');
}
$platform = input('platform/s');
$url = '';
if ($platform == 'android') {
$package = getUploadFile('package', true, ['apk']);
if (!$package['status']) {
$this->error($package['msg']);
} else {
$url = $package['data']['file'];
}
} else {
$url = input('appstore_url/s');
}
$data = array_merge($data,[
'package' => $url,
'create_at' => time(),
'create_ip' => $_SERVER['REMOTE_ADDR'],
'remark' => input('remark/s')
]);
$res = Db::name('app_version')->insert($data);
if ($res) {
$this->success('新增版本成功');
} else {
$this->error('新增版本失败');
}
}
}
<?php
namespace app\admin\controller;
use controller\BasicAdmin;
use service\DataService;
use service\NodeService;
use service\ToolsService;
use think\Request;
use think\Session;
use think\Db;
use think\captcha\Captcha;
use app\common\util\Sms;
use service\LogService;
/**
- 系统权限管理控制器
- Class Auth
- @package app\admin\controller
- @author Anyon <zoujingli@qq.com>
-
@date 2017/02/15 18:13
*/
class Auth extends BasicAdmin
{/**
- 默认数据模型
- @var string
*/
public $table = 'SystemAuth';
/**
- 权限列表
*/
public function index()
{
$this->title = '系统权限管理';
return parent::_list($this->table);
}
/**
- 权限授权
- @return string
*/
public function apply()
{
$auth_id = $this->request->get('id', '0');
$method = 'apply' . strtolower($this->request->get('action', '0'));
if (method_exists($this, $method)) {
return $this->$method($auth_id);
}
$this->assign('title', '节点授权');
return $this->_form($this->table, 'apply');
}
/**
- 读取授权节点
- @param $auth_id
*/
protected function _apply_getnode($auth_id)
{
$nodes = NodeService::get();
$checked = Db::name('SystemAuthNode')->where(['auth' => $auth_id])->column('node');
foreach ($nodes as &$node) {
$node['checked'] = in_array($node['node'], $checked);
}
$all = $this->_apply_filter(ToolsService::arr2tree($nodes, 'node', 'pnode', 'sub'));
$this->success('获取节点成功!', '', $all);
}
/**
- 保存授权节点
- @param $auth_id
*/
protected function _apply_save($auth_id)
{
list($data, $post) = [[], $this->request->post()];
foreach (isset($post['nodes']) ? $post['nodes'] : [] as $node) {
$data[] = ['auth' => $auth_id, 'node' => $node];
}
Db::name('SystemAuthNode')->where(['auth' => $auth_id])->delete();
Db::name('SystemAuthNode')->insertAll($data);
LogService::write('系统权限', '节点授权成功');
$this->success('节点授权更新成功!', '');
}
/**
- 节点数据拼装
- @param array $nodes
- @param int $level
- @return array
*/
protected function _apply_filter($nodes, $level = 1)
{
foreach ($nodes as $key => &$node) {
if (!empty($node['sub']) && is_array($node['sub'])) {
$node['sub'] = $this->_apply_filter($node['sub'], $level + 1);
}
}
return $nodes;
}
/**
- 权限添加
*/
public function add()
{
return $this->_form($this->table, 'form');
}
/**
- 权限编辑
*/
public function edit()
{
return $this->_form($this->table, 'form');
}
/**
- 权限禁用
*/
public function forbid()
{
if (DataService::update($this->table)) {
LogService::write('系统权限', '权限禁用成功');
$this->success("权限禁用成功!", '');
}
$this->error("权限禁用失败,请稍候再试!");
}
/**
- 权限恢复
*/
public function resume()
{
if (DataService::update($this->table)) {
LogService::write('系统权限', '权限启用成功');
$this->success("权限启用成功!", '');
}
$this->error("权限启用失败,请稍候再试!");
}
/**
- 权限删除
*/
public function del()
{
if (DataService::update($this->table)) {
$id = $this->request->post('id');
Db::name('SystemAuthNode')->where(['auth' => $id])->delete();
LogService::write('系统权限', '权限删除成功');
$this->success("权限删除成功!", '');
}
$this->error("权限删除失败,请稍候再试!");
}
/**
-
谷歌令牌验证
*/
public function google()
{
if (!session('user')) {
$this->error('未登录');
}
if(sysconf('is_google_auth') == 0) {
$this->error('系统未开启谷歌身份验证', '@admin');
}
$google_auth = session('google_auth');
if($google_auth) {
$this->redirect('@admin');
}
$ga = new \Util\Verify\PHPGangsta_GoogleAuthenticator();
$google_token = Db::name('system_user')->where('id',session('user')['id'])->value('google_secret_key');
if (!$this->request->isPost()) {
if($google_token == '') {
$secret = $ga->createSecret();
$qrCodeUrl = $ga->getQRCodeGoogleUrl(Request::instance()->domain(), $secret);
session('google_secret_key', $secret);
$this->assign('secret', $secret);
$this->assign('qrCodeUrl', $qrCodeUrl);} $this->assign('action_type', $google_token == '' ? 0 : 1); $this->assign('google_token', $google_token); return view();
} else {
$action_type = input('action_type/d', 0);
$code = $this->request->post('code', '', 'trim');
if($code == '') {
$this->error("请输入验证码");
}
if($action_type == 0) {//首次绑定
$google_secret_key = session('google_secret_key');
if(!$google_secret_key) {
$this->error("绑定失败,请刷新页面重试");
}
$oneCode = $ga->getCode($google_secret_key);
if($code !== $oneCode) {
$this->error("验证码错误");
} else {
$re = Db::name('system_user')->where(['id'=>session('user')['id']])->update(['google_secret_key'=>$google_secret_key]);
if(FALSE !== $re) {
session('google_auth', $oneCode);
session('google_secret_key', null);
$this->success("绑定成功", '@admin');
} else {
$this->error("绑定失败,请售后重试");
}
}
} else {
$google_secret_key = Db::name('system_user')->where(['id'=>session('user')['id']])->value('google_secret_key');
if($google_secret_key == '') {
$this->error("您未绑定谷歌身份验证器");
}
$captcha = $this->request->post('captcha_code', '', 'trim');
$captchaClass = new Captcha();
if(!$captchaClass->check($captcha)) {
$this->error('图形验证码错误!');
}
$oneCode = $ga->getCode($google_secret_key);
if($code != $oneCode) {
$this->error("身份验证码错误");
} else {
session('google_auth', $oneCode);
LogService::write('系统权限', '绑定谷歌身份验证器成功');
$this->success("验证通过,正在进入系统...", '@admin');
}
}}
}
public function resetGoogle()
{
if (!session('user')) {
$this->error('未登录');
}
if(sysconf('is_google_auth') == 0) {
$this->error('系统未开启谷歌身份验证');
}
$mobile = session('user')['phone'];
$google_auth = session('google_auth');
if($google_auth) {
$this->redirect('@admin');
}
if (!$this->request->isPost()) {
if($mobile) {
$mobile = substr($mobile, 0, 3).'****'.substr($mobile, 7);
}
$this->assign('mobile', $mobile);
return view();
} else {
$code = input('sms_code');
if($code == '') {
$this->error('请输入验证码');
}
$sms=new Sms();
if(!$sms->verifyCode($mobile, $code,'google_auth')){
$this->error($sms->getError());
}
$re = Db::name('system_user')->where(['id'=>session('user')['id']])->update(['google_secret_key'=>'']);
if(FALSE !== $re) {
LogService::write('系统权限', '谷歌身份验证器验证通过');
$this->success('验证通过,进入下一步...','admin/auth/google');
} else {
$this->error("重置失败");
}
}
}
//生成绑定谷歌身份验证器二维码(测试,部署生产环境时删除!)
public function bindGoogle()
{
$id = input('id/d');
if(!$id) {
return false;
}
$ga = new \Util\Verify\PHPGangsta_GoogleAuthenticator();
$google_secret_key = Db::name('system_user')->where(['id'=>$id])->value('google_secret_key');
if(!$google_secret_key) {
return false;
}
$qrCodeUrl = $ga->getQRCodeGoogleUrl(Request::instance()->domain(), $google_secret_key);
echo '<img src="'.$qrCodeUrl.'"">';die;
}/**
- 发送短信验证码
*/
public function sendSmsCode()
{
if (!session('user')) {
$this->error('未登录');
}
$mobile=session('user')['phone'];
if(!is_mobile_number($mobile)){
$this->error('不是有效的号码!');
}
$sms=new Sms();
$res=$sms->sendCode($mobile, 'google_auth');
if($res===false){
$this->error($sms->getError());
}
$this->success('已发送验证码,请注意查收!!');
}
}
发卡网源码演示及下载地址:fakaysw.top
<?php
namespace app\admin\controller;
use controller\BasicAdmin;
use think\Db;
class App extends BasicAdmin
{
public function index()
{
if (!$this->request->isPost()) {
return $this->fetch();
}
$version = input('version/s');
if(empty($version)){
$this->error('请输入版本号');
}
$data = [
'platform' => input('platform/s'),
'version' => $version,
];
//判断是否已经存在相同的版本号
$res = Db::name('app_version')->where($data)->find();
if($res){
$this->error('已存在相同版本');
}
$platform = input('platform/s');
$url = '';
if ($platform == 'android') {
$package = getUploadFile('package', true, ['apk']);
if (!$package['status']) {
$this->error($package['msg']);
} else {
$url = $package['data']['file'];
}
} else {
$url = input('appstore_url/s');
}
$data = array_merge($data,[
'package' => $url,
'create_at' => time(),
'create_ip' => $_SERVER['REMOTE_ADDR'],
'remark' => input('remark/s')
]);
$res = Db::name('app_version')->insert($data);
if ($res) {
$this->success('新增版本成功');
} else {
$this->error('新增版本失败');
}
}
}
<?php
namespace app\admin\controller;
use controller\BasicAdmin;
use service\DataService;
use service\NodeService;
use service\ToolsService;
use think\Request;
use think\Session;
use think\Db;
use think\captcha\Captcha;
use app\common\util\Sms;
use service\LogService;
/**
- 系统权限管理控制器
- Class Auth
- @package app\admin\controller
- @author Anyon <zoujingli@qq.com>
-
@date 2017/02/15 18:13
*/
class Auth extends BasicAdmin
{/**
- 默认数据模型
- @var string
*/
public $table = 'SystemAuth';
/**
- 权限列表
*/
public function index()
{
$this->title = '系统权限管理';
return parent::_list($this->table);
}
/**
- 权限授权
- @return string
*/
public function apply()
{
$auth_id = $this->request->get('id', '0');
$method = 'apply' . strtolower($this->request->get('action', '0'));
if (method_exists($this, $method)) {
return $this->$method($auth_id);
}
$this->assign('title', '节点授权');
return $this->_form($this->table, 'apply');
}
/**
- 读取授权节点
- @param $auth_id
*/
protected function _apply_getnode($auth_id)
{
$nodes = NodeService::get();
$checked = Db::name('SystemAuthNode')->where(['auth' => $auth_id])->column('node');
foreach ($nodes as &$node) {
$node['checked'] = in_array($node['node'], $checked);
}
$all = $this->_apply_filter(ToolsService::arr2tree($nodes, 'node', 'pnode', 'sub'));
$this->success('获取节点成功!', '', $all);
}
/**
- 保存授权节点
- @param $auth_id
*/
protected function _apply_save($auth_id)
{
list($data, $post) = [[], $this->request->post()];
foreach (isset($post['nodes']) ? $post['nodes'] : [] as $node) {
$data[] = ['auth' => $auth_id, 'node' => $node];
}
Db::name('SystemAuthNode')->where(['auth' => $auth_id])->delete();
Db::name('SystemAuthNode')->insertAll($data);
LogService::write('系统权限', '节点授权成功');
$this->success('节点授权更新成功!', '');
}
/**
- 节点数据拼装
- @param array $nodes
- @param int $level
- @return array
*/
protected function _apply_filter($nodes, $level = 1)
{
foreach ($nodes as $key => &$node) {
if (!empty($node['sub']) && is_array($node['sub'])) {
$node['sub'] = $this->_apply_filter($node['sub'], $level + 1);
}
}
return $nodes;
}
/**
- 权限添加
*/
public function add()
{
return $this->_form($this->table, 'form');
}
/**
- 权限编辑
*/
public function edit()
{
return $this->_form($this->table, 'form');
}
/**
- 权限禁用
*/
public function forbid()
{
if (DataService::update($this->table)) {
LogService::write('系统权限', '权限禁用成功');
$this->success("权限禁用成功!", '');
}
$this->error("权限禁用失败,请稍候再试!");
}
/**
- 权限恢复
*/
public function resume()
{
if (DataService::update($this->table)) {
LogService::write('系统权限', '权限启用成功');
$this->success("权限启用成功!", '');
}
$this->error("权限启用失败,请稍候再试!");
}
/**
- 权限删除
*/
public function del()
{
if (DataService::update($this->table)) {
$id = $this->request->post('id');
Db::name('SystemAuthNode')->where(['auth' => $id])->delete();
LogService::write('系统权限', '权限删除成功');
$this->success("权限删除成功!", '');
}
$this->error("权限删除失败,请稍候再试!");
}
/**
-
谷歌令牌验证
*/
public function google()
{
if (!session('user')) {
$this->error('未登录');
}
if(sysconf('is_google_auth') == 0) {
$this->error('系统未开启谷歌身份验证', '@admin');
}
$google_auth = session('google_auth');
if($google_auth) {
$this->redirect('@admin');
}
$ga = new \Util\Verify\PHPGangsta_GoogleAuthenticator();
$google_token = Db::name('system_user')->where('id',session('user')['id'])->value('google_secret_key');
if (!$this->request->isPost()) {
if($google_token == '') {
$secret = $ga->createSecret();
$qrCodeUrl = $ga->getQRCodeGoogleUrl(Request::instance()->domain(), $secret);
session('google_secret_key', $secret);
$this->assign('secret', $secret);
$this->assign('qrCodeUrl', $qrCodeUrl);} $this->assign('action_type', $google_token == '' ? 0 : 1); $this->assign('google_token', $google_token); return view();
} else {
$action_type = input('action_type/d', 0);
$code = $this->request->post('code', '', 'trim');
if($code == '') {
$this->error("请输入验证码");
}
if($action_type == 0) {//首次绑定
$google_secret_key = session('google_secret_key');
if(!$google_secret_key) {
$this->error("绑定失败,请刷新页面重试");
}
$oneCode = $ga->getCode($google_secret_key);
if($code !== $oneCode) {
$this->error("验证码错误");
} else {
$re = Db::name('system_user')->where(['id'=>session('user')['id']])->update(['google_secret_key'=>$google_secret_key]);
if(FALSE !== $re) {
session('google_auth', $oneCode);
session('google_secret_key', null);
$this->success("绑定成功", '@admin');
} else {
$this->error("绑定失败,请售后重试");
}
}
} else {
$google_secret_key = Db::name('system_user')->where(['id'=>session('user')['id']])->value('google_secret_key');
if($google_secret_key == '') {
$this->error("您未绑定谷歌身份验证器");
}
$captcha = $this->request->post('captcha_code', '', 'trim');
$captchaClass = new Captcha();
if(!$captchaClass->check($captcha)) {
$this->error('图形验证码错误!');
}
$oneCode = $ga->getCode($google_secret_key);
if($code != $oneCode) {
$this->error("身份验证码错误");
} else {
session('google_auth', $oneCode);
LogService::write('系统权限', '绑定谷歌身份验证器成功');
$this->success("验证通过,正在进入系统...", '@admin');
}
}}
}
public function resetGoogle()
{
if (!session('user')) {
$this->error('未登录');
}
if(sysconf('is_google_auth') == 0) {
$this->error('系统未开启谷歌身份验证');
}
$mobile = session('user')['phone'];
$google_auth = session('google_auth');
if($google_auth) {
$this->redirect('@admin');
}
if (!$this->request->isPost()) {
if($mobile) {
$mobile = substr($mobile, 0, 3).'****'.substr($mobile, 7);
}
$this->assign('mobile', $mobile);
return view();
} else {
$code = input('sms_code');
if($code == '') {
$this->error('请输入验证码');
}
$sms=new Sms();
if(!$sms->verifyCode($mobile, $code,'google_auth')){
$this->error($sms->getError());
}
$re = Db::name('system_user')->where(['id'=>session('user')['id']])->update(['google_secret_key'=>'']);
if(FALSE !== $re) {
LogService::write('系统权限', '谷歌身份验证器验证通过');
$this->success('验证通过,进入下一步...','admin/auth/google');
} else {
$this->error("重置失败");
}
}
}
//生成绑定谷歌身份验证器二维码(测试,部署生产环境时删除!)
public function bindGoogle()
{
$id = input('id/d');
if(!$id) {
return false;
}
$ga = new \Util\Verify\PHPGangsta_GoogleAuthenticator();
$google_secret_key = Db::name('system_user')->where(['id'=>$id])->value('google_secret_key');
if(!$google_secret_key) {
return false;
}
$qrCodeUrl = $ga->getQRCodeGoogleUrl(Request::instance()->domain(), $google_secret_key);
echo '<img src="'.$qrCodeUrl.'"">';die;
}/**
- 发送短信验证码
*/
public function sendSmsCode()
{
if (!session('user')) {
$this->error('未登录');
}
$mobile=session('user')['phone'];
if(!is_mobile_number($mobile)){
$this->error('不是有效的号码!');
}
$sms=new Sms();
$res=$sms->sendCode($mobile, 'google_auth');
if($res===false){
$this->error($sms->getError());
}
$this->success('已发送验证码,请注意查收!!');
}
}

UNIAPP前端工程师7000-10000
岗位职责:
1.根据工作安排高效、高质地完成代码编写,确保符合规范的前端代码规范;
2.负责公司项目的前端修改调试和开发工作,优化用户交互体验;
3.与设计团队紧密配合,能够实现实现设计师的设计想法;
4.与后端开发团队紧密配合,确保代码有效对接,优化页面前端性能。
任职要求:
1.大专及以上学历,有成熟微信小程序案例,微信公众平台开发项目优先;
2.熟悉各种Web客户端,尤其是主流Web浏览器的开发模式和特性;
3.精通HTML5/JavaScript/CSS3等Web开发技术,对性能优化有经验;
4.熟练微信小程序开发流程以及小程序相关API使用,熟悉微信平台接口及微信小程序功能研发;
5、熟练能用微信小程序的wmpf框架
6、熟练uniapp框架者;
7.具备工程化的前端思维,具备较好的问题分析与解决能力;
8.良好的代码编写习惯,有进取心、求知欲强烈、对工作充满热情!
工作地点:成都市郫都区创客公园
联系方式:可电子邮箱495881410@qq.com
岗位职责:
1.根据工作安排高效、高质地完成代码编写,确保符合规范的前端代码规范;
2.负责公司项目的前端修改调试和开发工作,优化用户交互体验;
3.与设计团队紧密配合,能够实现实现设计师的设计想法;
4.与后端开发团队紧密配合,确保代码有效对接,优化页面前端性能。
任职要求:
1.大专及以上学历,有成熟微信小程序案例,微信公众平台开发项目优先;
2.熟悉各种Web客户端,尤其是主流Web浏览器的开发模式和特性;
3.精通HTML5/JavaScript/CSS3等Web开发技术,对性能优化有经验;
4.熟练微信小程序开发流程以及小程序相关API使用,熟悉微信平台接口及微信小程序功能研发;
5、熟练能用微信小程序的wmpf框架
6、熟练uniapp框架者;
7.具备工程化的前端思维,具备较好的问题分析与解决能力;
8.良好的代码编写习惯,有进取心、求知欲强烈、对工作充满热情!
工作地点:成都市郫都区创客公园
联系方式:可电子邮箱495881410@qq.com

uniapp 显示 svga
注意hbuilder编译要v3
在manifest.json 文件下设置
"app-plus" : {
"compilerVersion" : 3,
}
具体内容在附件
注意hbuilder编译要v3
在manifest.json 文件下设置
"app-plus" : {
"compilerVersion" : 3,
}
具体内容在附件

uniCloud云数据库增删改查
一个H5页面,让你看懂数据库增删改查。
写在最前面
我是自学前端的小白,所以只能演示基本的操作,关于复杂的连表增删改查,还没有研究过。 就以这个demo
数据库为原型,完成查询、新增、修改、删除的基本操作示例。
1、查询,①在网站初始化时需要调用查询;②用户查询电户号时,需要调用查询;③新增或删除电户信息时,需要比对数据,也需要调用查询。
2、新增,分为①在demo
下,再新增_id
,并添加字段和值;②在指定_id
下指定位置新增。
3、更新,分为①覆盖式更新;②在同一个_id
下指定位置更新数据。
4、删除,分为①指定_id
全部删除;②在指定_id
下,指定位置删除数据。
在云函数写好之后,还需页面调用处理返回的数据,文末有示例。
一、准备云数据库
- 云数据库有两个,'initial'和'demo',后面有展开数据演示。
- 'initial',用于初始化页面。
- 'demo',用于增删改查。
二、编写云函数
- uniCloud数据库,允许在网页端直接使用
uniCloud.callFunction
函数调用数据库的数据。- 但是,建议使用云函数调用,这样数据更安全。</font>
- 云函数的主流是路由——自动匹配对应的云函数去处理数据,我还不会,所以就写了五个云函数,在页面要用哪个就调用哪个。
2.1 云函数默认目录。
uniCloud/cloudfunctions/云函数名称/云函数名称.js
2.2 uniCloud数据库操作基于mongoDB,可以查询相关文档。
三、获取数据的云函数
await db.collection('demo').field({}).get();
3.1 初始化页面获取数据的方法
- 初始化页面,需要调用的云数据库,名称
initial
,展开如下:
{
"_id":"603a0b27c9e7be00013b5e33",
"ArrList":["沙沟村","大东沟村","罗家坡村","小山岔村","渡口村","七家洼村"]
}
---------------华丽的---------分割线-------------
{
"_id":"603a120b20be4e000120b8f6",
"groupArr": {
"0": ["沙沟一变","沙沟二变","沙沟三变","同心一变","双明一变","双明二变"],
"1": ["一变","二变","三变"],
"2": ["一变","二变","三变","四变"],
"3": ["一变","二变","三变","四变","五变"]
--------后面-------还有------内容-------省略------
}
}
- 初始化云函数,名称也叫
initial
,代码如下: - get()获取的数据存放在data数组中,第一个
_id
的数据,就是data[0],第二个_id
的数据,就是data[1]
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
let [str] = event;
if(str ==='initial'){
let res = await db.collection('initial').field({_id:0,ArrList:1,'groupArr.0':1}).get();
//get()获取的数据存放在data数组中,第一个`_id`数据,就是data[0]
let cunList = res.data[0].ArrList;
//get()获取的数据存放在data数组中,第二个`_id`数据,就是data[1]
let zuList = res.data[1].groupArr[0];
//code的数字,只是为了前端if判断时好用,并没有什么实际意义。
return {
code:888,
msg:'初始化数据成功',
cunList,
zuList
}
}else{
return{
code:400,
msg:'您请求的数据格式有误'
}
}
}
- 前端页面调用的代码,在
onLoad
生命周期内,将查询的数据赋值给两个数组,再渲染到页面中(两个列表中)。 - 页面端调用的代码
this.$api.HandleUnicloud(cloudName, mydata){res=>{}}
,如何而来,文末有详解
export default {
data() {
return {
cun_list: [],
zu_list: []
}
}
onLoad() {
let mydata = ['initial'];
let cloudName = 'initial';
this.$api.HandleUnicloud(cloudName, mydata).then(res => {
this.cun_list = res.cunList;
this.zu_list = res.zuList;
});
}
}
3.2 <font color="red">★重点★</font> 查询返回指定字段的数据
-
示例
demo
数据库,由六部分组成,每一个_id
独立为一个单元。 -
数据库展开
{
"_id":"603eeaa40daee300011f18f4",
"villages": {
"name": "沙沟村",
"id": 0,
"groupArr": ["沙沟一变","沙沟二变","沙沟三变","同心一变","双明一变","双明二变"],
"group-1": [{"3102568889": "翟**"},{"3105360550": "李**"},{"3105360619": "马**"},..省略..],
"group-2": [{"3078734642": "刘**"},..省略..],
"group-3": [],
"group-4": [],
"group-6": []
}
}
------------华丽的-----------分割线------------------
{
"_id":"603eeab4e857bd0001690475",
"villages": {
"name": "大东沟村",
"id": 1,
"groupArr": ["一变","二变","三变"]
}
}
------------华丽的-----------分割线----------------
{
"_id":"603eeab4e857bd0001690475",
"villages": {
"name": "XXX村",
"id": 2,
"groupArr": ["一变","二变","三变","四变"]
}
}
-------后面----还有-----数据-----不再-----展示-----
field({})
,可以返回指定字段的内容,必须使用get()
方法才能获取到数据。1
表示显示,没有标注的数据不显示。但是_id
是默认显示的。field({'ArrList':1,_id:0})
,不显示_id
,查询关于ArrList
的信息,field({'villages.group-2':1})
<font color="red">查询 villages 数组或对象内 group-2 的内容。- 与变量相结合的查询方式,有二种:
const groupNum = "group-3";
field({[`villages.${groupNum}`]:1})
const groupNum = "group-4";
field({['villages.'+ groupNum]:true})
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
//event==mydata: { cunIndex: 0, groupName: 'group-1', userObj: { username: '', usernum: '' }, pageNum: 0, rowsNum: 10 }
let {cunIndex,groupName,userObj,pageNum,rowsNum} = event;
let resData = await db.collection('demo')
.field({_id:0,[`villages.${groupName}`]:1})
.get();
//resList等于当前村下的,当前变电组的,全部用户的信息
let resList = resData.data[`${cunIndex}`].villages[`${groupName}`];
//如果当前村的变电组不存在,或者变电组内没有数据时,调用
if(!resList||resList.length===0){
return {
code:400,
msg:'该村变电组内还未收录用户信息',
}
}
//这一段为翻页时调用
//请求的数据条数(rowsNum默认10条)
//pageNum当前点击的页码(由于是H5的原因默认是1)
let pageStarNum = (pageNum - 1) * rowsNum;
let pageEndNum = pageStarNum + rowsNum;
let pagesTotal = resList.length;
//pages表示返回的数据,在页面中总共要显示多少页
let pages = parseInt(pagesTotal/rowsNum);
//前端页面点击页码后,显示从第几条数据到第几条数据的列表
let resArr = resList.slice(pageStarNum,pageEndNum);
//resObj用于存放,数据库查找到的电户信息
let resObj = {};
//遍历当前变电组内所有的用户信息,当遍历的姓名与查询的姓名一致时
//把结果追加给resObj,使用合并对象的方法Object.assign(resObj,item)也行
resList.forEach(item=>{
if(Object.values(item)==userObj.username){
resObj = {...item}
}
})
//当用户没有输入姓名,直接查询,会获取全部列表
if(userObj.username===''){
return {
code:200,
msg:'当前查询的是:该变电组内所有用户的信息',
resArr,
pages
}
}
//当输入的姓名,查询不到时调用
//返回当前村、变电组,全部列表数据
//pages是总页数
if(Object.keys(resObj).length===0){
return {
code:404,
msg:'抱歉!该变电组内未收录此用户的信息',
resArr,
pages
}
}
//当输入的姓名,数据库中有时调用
//msg的信息可以使用模板字符串
return {
code:200,
msg:`「 ${userObj.username} 」的电户号,查询结果如下:`,
resObj
}
}
四、新增数据的云函数
4.1 在原数据外,新增一个_id,add()
- 新增单一数据,用大括号包裹数据
{"name": "张三"}
。 - 新增多条数据,用中括号包裹数据
[{"name": "张三"},{"name": "李四"},{"name": "王五"}]
。
const db = uniCloud.database();
exports.main = async (event, context) => {
let resData = await db.collection('demo')
.add([{"name": "张三"},{"name": "李四"},{"name": "王五"}]);
let resList = await db.collection('demo').get();
return {
code:200,
msg:'添加数据成功',
resList
}
};//数据返回结果
{
"code": 200,
"msg": "添加数据成功",
"resList": {
"data": [{
"_id": "60210b53ef338d00016d2404",
....此处 .... 省略 ....一万字....
},
{
"_id": "6038d46620be4e00011e5cf4",
"name": "张三"
},
{
"_id": "6038d46620be4e00011e5cf5",
"name": "李四"
},
{
"_id": "6038d46620be4e00011e5cf6",
"name": "王五"
}
}]
}
4.2 在指定_id内,指定位置新增。
-
doc('_id').update();
方法可用于更改,也可用于新增。 -
普通数组添加、删除数据,官方文档中有示例,这里演示的是,数据为对象的数组
"group-1":[{key:value},{key:vlaue}]
如何新增。 -
update(),需紧随
doc()
之后,doc()
内写指定数据的_id
,因为一个集合内可能有多个_id
-
在
update()
内引用变量,需要使用[`${变量名}`]
-
在数组尾部新增对象,可以在中括号内写模板字符串
dbCmd.push([{...addUserObj}])
'use strict';
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
let {cunIndex,groupName,userObj} = event;
if(userObj.username==''||userObj.usernum==''){
return{
code:400,
msg:'新增数据不能为空'
}
}
let resData = await db.collection('demo').field({_id: 1,[`villages.${groupName}`]: 1}).get();
//用于获取_id,存放与data[{_id:***},{_id:***},{_id:***},***]中
let id = resData.data[`${cunIndex}`]['_id'];
let groupArr = resData.data[`${cunIndex}`].villages[`${groupName}`];
let isTrue = true;
//先查询,用户要新增的电户号码,在数据库中,有没有,有就赋值false
if (groupArr) {
groupArr.forEach(val=>{
if(Object.keys(val)==userObj.usernum){
isTrue = false;
}
});
//如果数据库中没有该电户号码,就在对应村、变电组的尾部新增该数据
if(isTrue){
let addUserObj = {[`${userObj.usernum}`]:userObj.username};
let resSucc = await db.collection('demo')
.doc(`${id}`)
.update({
villages: {
[`${groupName}`]: dbCmd.push([{...addUserObj}])
}
})
return {
code: 200,
msg: '数据添加成功',
resSucc
}
//当数据库中有该电户号码时,就提示已经存在
}else{
return {
code: 400,
msg: `抱歉!电户号「 ${userObj.usernum} 」已经存在`
}
}
}
//如果该村还未创建该变电组,就新建变电组,之后再新增用户信息
if (!groupArr) {
let resSucc = await db.collection('demo')
.doc(`${id}`)
.update({
villages: {
[`${groupName}`]: dbCmd.set([{
[`${userObj.usernum}`]: userObj.username
}])
}
})
return {
code: 200,
msg: '创建变电组成功,数据添加成功',
resSucc
}
}
}
五、更新数据的云函数
5.1 覆盖式更新
- 覆盖式更新的意义不大,会将原数据彻底清除,一般情况下用不到。
update({'villages':dbCmd.set({key:value})})
将villages做为字段,后面跟一个对象
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
let resSucc = await db.collection('demo')
.doc("600bfa4d7f06f30001b47259")
.update({
'villages':dbCmd.set({
"6640059601": "张三"
})
}
);
let resObj = await db.collection('demo').get();
return {
code:200,
resObj,
resSucc
}
}
//返回的数据结果 villages下只剩下一个对象了
"villages": {"6640059601":"张三"}
5.2 指定_id
下,指定位置更新。
- 指定位置更新,同上面的update()方法一致,这里省略。
六、删除数据的云函数
6.1 删除指定_id的数据库的全部数据
-
collection.doc(_id).remove()
-
doc()
内只能写字符串或者数字,可以使用ES6模板字符串doc(`${id}`)
// 删除指定_id的数据
const db = uniCloud.database();
exports.main = async (event, context) => {
const id = '60388f7eb6ce210001cbbf14';
await db.collection('demo')
.doc(`${id}`)
.remove();
let resData = await db.collection('demo').get();
return resData;
};
6.2 删除指定位置的数据
- 在update()内使用remove(),方法挂载在command下,不能用于数组,删除后,数组原索引位置会变成null。但是可以用于对象,删除key就等于删除了该对象。doc(`${id}`).update({villages:{name:dbCmd.remove()}})
- 更新数组,可以先获取数组,再修改数组,最后把新数组更新到原位置即可。update({villages:{[`${groupName}`]:[...groupArr]}})
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
let {cunIndex,groupName,userObj} = event;
let resData = await db.collection('demo').field({_id: 1,[`villages.${groupName}`]: 1}).get();
let id = resData.data[`${cunIndex}`]['_id'];
let groupArr = resData.data[`${cunIndex}`].villages[`${groupName}`];
let isTrue = false;
var index = 0;
if (!groupArr) {
return {
code: 400,
msg: '抱歉!该村还未创建此变电组数据',
resSucc
}
};
groupArr.forEach((val,i)=>{
if(Object.keys(val)==userObj.usernum){
isTrue = true;
index = i
}
});
//先查询数据在数组中的索引,使用splice,删除数据,把获得的新数组,更新到原位置处
if(isTrue){
groupArr.splice([`${index}`],1);
let resData = await db.collection('demo')
.doc(`${id}`)
.update({
villages:{
[`${groupName}`]:[...groupArr]
}
})
return {
code: 200,
msg: `「 ${userObj.usernum} 」数据删除成功`,
index,
groupArr,
resData
}
};
return {
code: 400,
msg: '数据删除失败,原因:电户号错误'
}
}
七、处理云函数返回数据的工具函数
- 工具函数的路径
common/api/index.js
- HandleUnicloud有两个参数,用于
uniCloud.callFunction({name,data})
传参。 cloudName
表示,需要调用哪个云函数。mydata
表示,用户向云函数传递的数据。
const HandleUnicloud = (cloudName,mydata)=>{
return new Promise((reslove,reject)=>{
uniCloud.callFunction({
name:cloudName,
data:mydata
}).then(res=>{
if(res.result){
reslove(res.result)
}else{
reject(res.result)
}
}).catch(res=>{
console.log(res);
})
});
};
export default{
HandleUnicloud
}
八、全局注册处理云函数数据的工具函数
- 先引入
import api from './common/api'
- 再注册
Vue.prototype.$api = api
import Vue from 'vue'
import App from './App'
import api from './common/api'
Vue.config.productionTip = false
Vue.prototype.$api = api
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
九、页面调用的方法
this.$api.HandleUnicloud()
addData() {
//用户传给云函数的数据,赋值给mydata
let mydata = this.mydata;
//当前需要调用的云函数名称
let cloudName = 'UpdateAdd';
//用于检查姓名和电户号码的正则函数checkName()和checkNum()
if (!this.checkName(this.mydata.userObj.username) || !this.checkNum(this.mydata.userObj.usernum)) {
this.tip = '抱歉,姓名和电户号,数据有误!';
return;
}
//有确定和取消按键的模态框
uni.showModal({
title: '请选择',
content: `您确定要添加${mydata.userObj.username}吗?`,
cancelText:'取消添加',
confirmText:'确定添加',
//这里应当使用箭头函数,否则影响this.$api和this.tip的使用
success: res=> {
if (res.confirm) {
this.$api.HandleUnicloud(cloudName, mydata).then(v => {
this.tip = v.msg;
uni.showLoading({
title: this.tip
});
setTimeout(() => {
uni.hideLoading();
}, 1000);
});
} else if (res.cancel) {
this.tip = '选择了取消!'
}
}
});
}
十、写在最后
非常感谢,DCloud公司提供如此强大的生态系统,让我们去学习进步的效率大大的提升。
最后附上H5白~嫖建站的最后一关,跨域配置问题,将前端网页托管——参数配置——默认网址,复制粘贴到跨域配置——新增域名中,即可手机,PC端都能正常访问了。
目前uniCloud</font>提供了,免费的阿里云空间,</font>完全可以满足个人用户的建站使用。
只需要在https://unicloud.dcloud.net.cn/login申请账号就可以获得:
1、一个免费的云数据库,用于保存JSON格式的数据
2、一个免费的存储云函数的空间,用于保存可以在云端调用修改云数据库数据的函数,空间环境为nodejs,操作基于mongoDB,有所改动。
3、一个免费的云存储,用于保存图片、视频、文件等,并能够提供对应的访问地址
4、一个免费的网页托管,自动生成可访问的网址,只需处理跨域配置即可。
个人博客地址
一个H5页面,让你看懂数据库增删改查。
写在最前面
我是自学前端的小白,所以只能演示基本的操作,关于复杂的连表增删改查,还没有研究过。 就以这个demo
数据库为原型,完成查询、新增、修改、删除的基本操作示例。
1、查询,①在网站初始化时需要调用查询;②用户查询电户号时,需要调用查询;③新增或删除电户信息时,需要比对数据,也需要调用查询。
2、新增,分为①在demo
下,再新增_id
,并添加字段和值;②在指定_id
下指定位置新增。
3、更新,分为①覆盖式更新;②在同一个_id
下指定位置更新数据。
4、删除,分为①指定_id
全部删除;②在指定_id
下,指定位置删除数据。
在云函数写好之后,还需页面调用处理返回的数据,文末有示例。
一、准备云数据库
- 云数据库有两个,'initial'和'demo',后面有展开数据演示。
- 'initial',用于初始化页面。
- 'demo',用于增删改查。
二、编写云函数
- uniCloud数据库,允许在网页端直接使用
uniCloud.callFunction
函数调用数据库的数据。- 但是,建议使用云函数调用,这样数据更安全。</font>
- 云函数的主流是路由——自动匹配对应的云函数去处理数据,我还不会,所以就写了五个云函数,在页面要用哪个就调用哪个。
2.1 云函数默认目录。
uniCloud/cloudfunctions/云函数名称/云函数名称.js
2.2 uniCloud数据库操作基于mongoDB,可以查询相关文档。
三、获取数据的云函数
await db.collection('demo').field({}).get();
3.1 初始化页面获取数据的方法
- 初始化页面,需要调用的云数据库,名称
initial
,展开如下:
{
"_id":"603a0b27c9e7be00013b5e33",
"ArrList":["沙沟村","大东沟村","罗家坡村","小山岔村","渡口村","七家洼村"]
}
---------------华丽的---------分割线-------------
{
"_id":"603a120b20be4e000120b8f6",
"groupArr": {
"0": ["沙沟一变","沙沟二变","沙沟三变","同心一变","双明一变","双明二变"],
"1": ["一变","二变","三变"],
"2": ["一变","二变","三变","四变"],
"3": ["一变","二变","三变","四变","五变"]
--------后面-------还有------内容-------省略------
}
}
- 初始化云函数,名称也叫
initial
,代码如下: - get()获取的数据存放在data数组中,第一个
_id
的数据,就是data[0],第二个_id
的数据,就是data[1]
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
let [str] = event;
if(str ==='initial'){
let res = await db.collection('initial').field({_id:0,ArrList:1,'groupArr.0':1}).get();
//get()获取的数据存放在data数组中,第一个`_id`数据,就是data[0]
let cunList = res.data[0].ArrList;
//get()获取的数据存放在data数组中,第二个`_id`数据,就是data[1]
let zuList = res.data[1].groupArr[0];
//code的数字,只是为了前端if判断时好用,并没有什么实际意义。
return {
code:888,
msg:'初始化数据成功',
cunList,
zuList
}
}else{
return{
code:400,
msg:'您请求的数据格式有误'
}
}
}
- 前端页面调用的代码,在
onLoad
生命周期内,将查询的数据赋值给两个数组,再渲染到页面中(两个列表中)。 - 页面端调用的代码
this.$api.HandleUnicloud(cloudName, mydata){res=>{}}
,如何而来,文末有详解
export default {
data() {
return {
cun_list: [],
zu_list: []
}
}
onLoad() {
let mydata = ['initial'];
let cloudName = 'initial';
this.$api.HandleUnicloud(cloudName, mydata).then(res => {
this.cun_list = res.cunList;
this.zu_list = res.zuList;
});
}
}
3.2 <font color="red">★重点★</font> 查询返回指定字段的数据
-
示例
demo
数据库,由六部分组成,每一个_id
独立为一个单元。 -
数据库展开
{
"_id":"603eeaa40daee300011f18f4",
"villages": {
"name": "沙沟村",
"id": 0,
"groupArr": ["沙沟一变","沙沟二变","沙沟三变","同心一变","双明一变","双明二变"],
"group-1": [{"3102568889": "翟**"},{"3105360550": "李**"},{"3105360619": "马**"},..省略..],
"group-2": [{"3078734642": "刘**"},..省略..],
"group-3": [],
"group-4": [],
"group-6": []
}
}
------------华丽的-----------分割线------------------
{
"_id":"603eeab4e857bd0001690475",
"villages": {
"name": "大东沟村",
"id": 1,
"groupArr": ["一变","二变","三变"]
}
}
------------华丽的-----------分割线----------------
{
"_id":"603eeab4e857bd0001690475",
"villages": {
"name": "XXX村",
"id": 2,
"groupArr": ["一变","二变","三变","四变"]
}
}
-------后面----还有-----数据-----不再-----展示-----
field({})
,可以返回指定字段的内容,必须使用get()
方法才能获取到数据。1
表示显示,没有标注的数据不显示。但是_id
是默认显示的。field({'ArrList':1,_id:0})
,不显示_id
,查询关于ArrList
的信息,field({'villages.group-2':1})
<font color="red">查询 villages 数组或对象内 group-2 的内容。- 与变量相结合的查询方式,有二种:
const groupNum = "group-3";
field({[`villages.${groupNum}`]:1})
const groupNum = "group-4";
field({['villages.'+ groupNum]:true})
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
//event==mydata: { cunIndex: 0, groupName: 'group-1', userObj: { username: '', usernum: '' }, pageNum: 0, rowsNum: 10 }
let {cunIndex,groupName,userObj,pageNum,rowsNum} = event;
let resData = await db.collection('demo')
.field({_id:0,[`villages.${groupName}`]:1})
.get();
//resList等于当前村下的,当前变电组的,全部用户的信息
let resList = resData.data[`${cunIndex}`].villages[`${groupName}`];
//如果当前村的变电组不存在,或者变电组内没有数据时,调用
if(!resList||resList.length===0){
return {
code:400,
msg:'该村变电组内还未收录用户信息',
}
}
//这一段为翻页时调用
//请求的数据条数(rowsNum默认10条)
//pageNum当前点击的页码(由于是H5的原因默认是1)
let pageStarNum = (pageNum - 1) * rowsNum;
let pageEndNum = pageStarNum + rowsNum;
let pagesTotal = resList.length;
//pages表示返回的数据,在页面中总共要显示多少页
let pages = parseInt(pagesTotal/rowsNum);
//前端页面点击页码后,显示从第几条数据到第几条数据的列表
let resArr = resList.slice(pageStarNum,pageEndNum);
//resObj用于存放,数据库查找到的电户信息
let resObj = {};
//遍历当前变电组内所有的用户信息,当遍历的姓名与查询的姓名一致时
//把结果追加给resObj,使用合并对象的方法Object.assign(resObj,item)也行
resList.forEach(item=>{
if(Object.values(item)==userObj.username){
resObj = {...item}
}
})
//当用户没有输入姓名,直接查询,会获取全部列表
if(userObj.username===''){
return {
code:200,
msg:'当前查询的是:该变电组内所有用户的信息',
resArr,
pages
}
}
//当输入的姓名,查询不到时调用
//返回当前村、变电组,全部列表数据
//pages是总页数
if(Object.keys(resObj).length===0){
return {
code:404,
msg:'抱歉!该变电组内未收录此用户的信息',
resArr,
pages
}
}
//当输入的姓名,数据库中有时调用
//msg的信息可以使用模板字符串
return {
code:200,
msg:`「 ${userObj.username} 」的电户号,查询结果如下:`,
resObj
}
}
四、新增数据的云函数
4.1 在原数据外,新增一个_id,add()
- 新增单一数据,用大括号包裹数据
{"name": "张三"}
。 - 新增多条数据,用中括号包裹数据
[{"name": "张三"},{"name": "李四"},{"name": "王五"}]
。
const db = uniCloud.database();
exports.main = async (event, context) => {
let resData = await db.collection('demo')
.add([{"name": "张三"},{"name": "李四"},{"name": "王五"}]);
let resList = await db.collection('demo').get();
return {
code:200,
msg:'添加数据成功',
resList
}
};//数据返回结果
{
"code": 200,
"msg": "添加数据成功",
"resList": {
"data": [{
"_id": "60210b53ef338d00016d2404",
....此处 .... 省略 ....一万字....
},
{
"_id": "6038d46620be4e00011e5cf4",
"name": "张三"
},
{
"_id": "6038d46620be4e00011e5cf5",
"name": "李四"
},
{
"_id": "6038d46620be4e00011e5cf6",
"name": "王五"
}
}]
}
4.2 在指定_id内,指定位置新增。
-
doc('_id').update();
方法可用于更改,也可用于新增。 -
普通数组添加、删除数据,官方文档中有示例,这里演示的是,数据为对象的数组
"group-1":[{key:value},{key:vlaue}]
如何新增。 -
update(),需紧随
doc()
之后,doc()
内写指定数据的_id
,因为一个集合内可能有多个_id
-
在
update()
内引用变量,需要使用[`${变量名}`]
-
在数组尾部新增对象,可以在中括号内写模板字符串
dbCmd.push([{...addUserObj}])
'use strict';
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
let {cunIndex,groupName,userObj} = event;
if(userObj.username==''||userObj.usernum==''){
return{
code:400,
msg:'新增数据不能为空'
}
}
let resData = await db.collection('demo').field({_id: 1,[`villages.${groupName}`]: 1}).get();
//用于获取_id,存放与data[{_id:***},{_id:***},{_id:***},***]中
let id = resData.data[`${cunIndex}`]['_id'];
let groupArr = resData.data[`${cunIndex}`].villages[`${groupName}`];
let isTrue = true;
//先查询,用户要新增的电户号码,在数据库中,有没有,有就赋值false
if (groupArr) {
groupArr.forEach(val=>{
if(Object.keys(val)==userObj.usernum){
isTrue = false;
}
});
//如果数据库中没有该电户号码,就在对应村、变电组的尾部新增该数据
if(isTrue){
let addUserObj = {[`${userObj.usernum}`]:userObj.username};
let resSucc = await db.collection('demo')
.doc(`${id}`)
.update({
villages: {
[`${groupName}`]: dbCmd.push([{...addUserObj}])
}
})
return {
code: 200,
msg: '数据添加成功',
resSucc
}
//当数据库中有该电户号码时,就提示已经存在
}else{
return {
code: 400,
msg: `抱歉!电户号「 ${userObj.usernum} 」已经存在`
}
}
}
//如果该村还未创建该变电组,就新建变电组,之后再新增用户信息
if (!groupArr) {
let resSucc = await db.collection('demo')
.doc(`${id}`)
.update({
villages: {
[`${groupName}`]: dbCmd.set([{
[`${userObj.usernum}`]: userObj.username
}])
}
})
return {
code: 200,
msg: '创建变电组成功,数据添加成功',
resSucc
}
}
}
五、更新数据的云函数
5.1 覆盖式更新
- 覆盖式更新的意义不大,会将原数据彻底清除,一般情况下用不到。
update({'villages':dbCmd.set({key:value})})
将villages做为字段,后面跟一个对象
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
let resSucc = await db.collection('demo')
.doc("600bfa4d7f06f30001b47259")
.update({
'villages':dbCmd.set({
"6640059601": "张三"
})
}
);
let resObj = await db.collection('demo').get();
return {
code:200,
resObj,
resSucc
}
}
//返回的数据结果 villages下只剩下一个对象了
"villages": {"6640059601":"张三"}
5.2 指定_id
下,指定位置更新。
- 指定位置更新,同上面的update()方法一致,这里省略。
六、删除数据的云函数
6.1 删除指定_id的数据库的全部数据
-
collection.doc(_id).remove()
-
doc()
内只能写字符串或者数字,可以使用ES6模板字符串doc(`${id}`)
// 删除指定_id的数据
const db = uniCloud.database();
exports.main = async (event, context) => {
const id = '60388f7eb6ce210001cbbf14';
await db.collection('demo')
.doc(`${id}`)
.remove();
let resData = await db.collection('demo').get();
return resData;
};
6.2 删除指定位置的数据
- 在update()内使用remove(),方法挂载在command下,不能用于数组,删除后,数组原索引位置会变成null。但是可以用于对象,删除key就等于删除了该对象。doc(`${id}`).update({villages:{name:dbCmd.remove()}})
- 更新数组,可以先获取数组,再修改数组,最后把新数组更新到原位置即可。update({villages:{[`${groupName}`]:[...groupArr]}})
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
let {cunIndex,groupName,userObj} = event;
let resData = await db.collection('demo').field({_id: 1,[`villages.${groupName}`]: 1}).get();
let id = resData.data[`${cunIndex}`]['_id'];
let groupArr = resData.data[`${cunIndex}`].villages[`${groupName}`];
let isTrue = false;
var index = 0;
if (!groupArr) {
return {
code: 400,
msg: '抱歉!该村还未创建此变电组数据',
resSucc
}
};
groupArr.forEach((val,i)=>{
if(Object.keys(val)==userObj.usernum){
isTrue = true;
index = i
}
});
//先查询数据在数组中的索引,使用splice,删除数据,把获得的新数组,更新到原位置处
if(isTrue){
groupArr.splice([`${index}`],1);
let resData = await db.collection('demo')
.doc(`${id}`)
.update({
villages:{
[`${groupName}`]:[...groupArr]
}
})
return {
code: 200,
msg: `「 ${userObj.usernum} 」数据删除成功`,
index,
groupArr,
resData
}
};
return {
code: 400,
msg: '数据删除失败,原因:电户号错误'
}
}
七、处理云函数返回数据的工具函数
- 工具函数的路径
common/api/index.js
- HandleUnicloud有两个参数,用于
uniCloud.callFunction({name,data})
传参。 cloudName
表示,需要调用哪个云函数。mydata
表示,用户向云函数传递的数据。
const HandleUnicloud = (cloudName,mydata)=>{
return new Promise((reslove,reject)=>{
uniCloud.callFunction({
name:cloudName,
data:mydata
}).then(res=>{
if(res.result){
reslove(res.result)
}else{
reject(res.result)
}
}).catch(res=>{
console.log(res);
})
});
};
export default{
HandleUnicloud
}
八、全局注册处理云函数数据的工具函数
- 先引入
import api from './common/api'
- 再注册
Vue.prototype.$api = api
import Vue from 'vue'
import App from './App'
import api from './common/api'
Vue.config.productionTip = false
Vue.prototype.$api = api
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
九、页面调用的方法
this.$api.HandleUnicloud()
addData() {
//用户传给云函数的数据,赋值给mydata
let mydata = this.mydata;
//当前需要调用的云函数名称
let cloudName = 'UpdateAdd';
//用于检查姓名和电户号码的正则函数checkName()和checkNum()
if (!this.checkName(this.mydata.userObj.username) || !this.checkNum(this.mydata.userObj.usernum)) {
this.tip = '抱歉,姓名和电户号,数据有误!';
return;
}
//有确定和取消按键的模态框
uni.showModal({
title: '请选择',
content: `您确定要添加${mydata.userObj.username}吗?`,
cancelText:'取消添加',
confirmText:'确定添加',
//这里应当使用箭头函数,否则影响this.$api和this.tip的使用
success: res=> {
if (res.confirm) {
this.$api.HandleUnicloud(cloudName, mydata).then(v => {
this.tip = v.msg;
uni.showLoading({
title: this.tip
});
setTimeout(() => {
uni.hideLoading();
}, 1000);
});
} else if (res.cancel) {
this.tip = '选择了取消!'
}
}
});
}
十、写在最后
非常感谢,DCloud公司提供如此强大的生态系统,让我们去学习进步的效率大大的提升。
最后附上H5白~嫖建站的最后一关,跨域配置问题,将前端网页托管——参数配置——默认网址,复制粘贴到跨域配置——新增域名中,即可手机,PC端都能正常访问了。
目前uniCloud</font>提供了,免费的阿里云空间,</font>完全可以满足个人用户的建站使用。
只需要在https://unicloud.dcloud.net.cn/login申请账号就可以获得:
1、一个免费的云数据库,用于保存JSON格式的数据
2、一个免费的存储云函数的空间,用于保存可以在云端调用修改云数据库数据的函数,空间环境为nodejs,操作基于mongoDB,有所改动。
3、一个免费的云存储,用于保存图片、视频、文件等,并能够提供对应的访问地址
4、一个免费的网页托管,自动生成可访问的网址,只需处理跨域配置即可。
个人博客地址

【分享】uniCloud云函数结合nodemailer发送邮件的方法
网上找的node发邮件,用到最多的是nodemailer,于是利用百度出来的代码,直接运行在uniCloud,本地运行发送成功,但是云端一直报错。
仔细看了报错内容,提到Thread,所以猜测代码里新建了线程去发邮件。
为了找到如何用当前线程发,第一时间想到的是nodemailer的官方文档:https://nodemailer.com/about/
结合官方文档,写了个可以在uniCloud云端正常发邮件,并且亲测成功的代码:
'use strict';
const nodemailer = require('nodemailer') // 记得在当前文件夹执行npm install nodemailer后才能使用
exports.main = async (event, context) => {
let transporter = nodemailer.createTransport({
host: 'smtp.126.com',
secureConnection: true,
port: 465,
secure: true,
auth: {
user: 'yourname@126.com',
pass: 'SMTP授权码'
}
})
const info = await transporter.sendMail({
from: '"邮箱昵称"<yourname@126.com>',
to: 'receiver@163.com',
subject: '主题',
html: '<h1>HTML代码</h1>',
text: '文本'
})
if (info.messageId) {
return {code: 0, msg: '发送成功'}
} else {
return {code: 1, msg: '发送失败', info}
}
}
代码里最关键的是await transporter.sendMail这行,这样写才是在当前线程发
百度上找到的大部分人是这么写的:
transporter.sendMail({
from: '"邮箱昵称"<yourname@126.com>',
to: 'receiver@163.com',
subject: '主题',
html: '<h1>HTML代码</h1>',
text: '文本'
}, (error, info) => {
if (error) {
return console.log(error);
}
console.log(info)
})
这样写的话会新建线程,这在普通的node环境当然没错,但是uniCloud却报了关于线程的错误,猜测是uniCloud不允许多线程
网上找的node发邮件,用到最多的是nodemailer,于是利用百度出来的代码,直接运行在uniCloud,本地运行发送成功,但是云端一直报错。
仔细看了报错内容,提到Thread,所以猜测代码里新建了线程去发邮件。
为了找到如何用当前线程发,第一时间想到的是nodemailer的官方文档:https://nodemailer.com/about/
结合官方文档,写了个可以在uniCloud云端正常发邮件,并且亲测成功的代码:
'use strict';
const nodemailer = require('nodemailer') // 记得在当前文件夹执行npm install nodemailer后才能使用
exports.main = async (event, context) => {
let transporter = nodemailer.createTransport({
host: 'smtp.126.com',
secureConnection: true,
port: 465,
secure: true,
auth: {
user: 'yourname@126.com',
pass: 'SMTP授权码'
}
})
const info = await transporter.sendMail({
from: '"邮箱昵称"<yourname@126.com>',
to: 'receiver@163.com',
subject: '主题',
html: '<h1>HTML代码</h1>',
text: '文本'
})
if (info.messageId) {
return {code: 0, msg: '发送成功'}
} else {
return {code: 1, msg: '发送失败', info}
}
}
代码里最关键的是await transporter.sendMail这行,这样写才是在当前线程发
百度上找到的大部分人是这么写的:
transporter.sendMail({
from: '"邮箱昵称"<yourname@126.com>',
to: 'receiver@163.com',
subject: '主题',
html: '<h1>HTML代码</h1>',
text: '文本'
}, (error, info) => {
if (error) {
return console.log(error);
}
console.log(info)
})
这样写的话会新建线程,这在普通的node环境当然没错,但是uniCloud却报了关于线程的错误,猜测是uniCloud不允许多线程
原文出处:https://coding3.com/archives/uniCloud-nodemailer.html
收起阅读 »
红包雨--简单实现,没有过度的修饰
<template>
<view class="home">
<view class="content">
<view @animationend="runend(index)" @animationstart="runstart(index)" v-for="(item,index) in packStyle" :key="index" class="envelope" :style="item">
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
packStyle: []
};
},
onLoad() {
// 随即生成红包
this.createRedPack();
},
mounted() {
},
onReady() {
},
methods: {
runstart(key){
if(key===0){
console.log('监听动画开始');
}
},
runend(key){
if(key===this.packStyle.length-1){
console.log('监听动画结束---下一波红包开始');
this.createRedPack()
}
},
createRedPack(){
// 随机生成30个红包
var initNumber = 0;
for (var i = 0; i < 60; i++) {
let lefts = (Math.floor(Math.random()*5+5)); // 随机边距
let delay = Math.floor(Math.random()*5+2); // 延迟时间
initNumber+=lefts; // 确保唯一,不让红包出现重叠现象
this.packStyle.push({
'left': initNumber+'%',
'top': lefts+'px',
'animation-delay': delay/2+'s'
})
}
}
}
};
</script>
<style>
.home {
width: 100%;
height: 100%;
}
.content {
position: relative;
height: 100%;
background: #fff;
overflow: hidden;
}
.envelope {
position: fixed;
opacity: 0;
animation: drops 1.2s cubic-bezier(.22,.22,.39,.26) 1;
width: 60px;
height: 60px;
background: url(../../static/hongbaotu.png) no-repeat;
/* background-color: #007AFF; */
background-size: 60px 60px;
}
@keyframes drops {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
opacity: 0;
transform: translate3d(10px, 100vh, -10px);
}
}
</style>
<template>
<view class="home">
<view class="content">
<view @animationend="runend(index)" @animationstart="runstart(index)" v-for="(item,index) in packStyle" :key="index" class="envelope" :style="item">
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
packStyle: []
};
},
onLoad() {
// 随即生成红包
this.createRedPack();
},
mounted() {
},
onReady() {
},
methods: {
runstart(key){
if(key===0){
console.log('监听动画开始');
}
},
runend(key){
if(key===this.packStyle.length-1){
console.log('监听动画结束---下一波红包开始');
this.createRedPack()
}
},
createRedPack(){
// 随机生成30个红包
var initNumber = 0;
for (var i = 0; i < 60; i++) {
let lefts = (Math.floor(Math.random()*5+5)); // 随机边距
let delay = Math.floor(Math.random()*5+2); // 延迟时间
initNumber+=lefts; // 确保唯一,不让红包出现重叠现象
this.packStyle.push({
'left': initNumber+'%',
'top': lefts+'px',
'animation-delay': delay/2+'s'
})
}
}
}
};
</script>
<style>
.home {
width: 100%;
height: 100%;
}
.content {
position: relative;
height: 100%;
background: #fff;
overflow: hidden;
}
.envelope {
position: fixed;
opacity: 0;
animation: drops 1.2s cubic-bezier(.22,.22,.39,.26) 1;
width: 60px;
height: 60px;
background: url(../../static/hongbaotu.png) no-repeat;
/* background-color: #007AFF; */
background-size: 60px 60px;
}
@keyframes drops {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
opacity: 0;
transform: translate3d(10px, 100vh, -10px);
}
}
</style>
收起阅读 »

安卓离线打包小米推送Register mipush appId or appKey is null or empty的解决方法
安卓离线打包,小米离线推送,打开页面,提示Register mipush appId or appKey is null or empty
问了官方人员,见这个帖子。https://ask.dcloud.net.cn/question/118126
我们分3步来分析可能会出什么问题。
第一步、引入lib:aps-release.aar和aps-unipush-release.aar
第二步、build配置key
第三步、工程的xml引入这个key
第一步,类库没有引入。
因为我的华为测试还好的,可以离线推送,所以我首先排除掉这个问题,我尝试把这两个类库去掉,安装好app,会提示push库不存在。
所以,排除掉这个问题。
第二步、build配置key
这步,似乎也没啥好看的,按照官方的离线打包文档,就是这么写的。
第三步、工程的xml引入这个key
后来读了push的安卓源代码。
发现是这步的问题,meta-data的位置放错了,要放到application后面,但奇怪的是华为的也在前面,不知道为什么能识别。
如果大家觉得受益匪浅的话,记得打赏一下哈。有问题加我QQ:13040
安卓离线打包,小米离线推送,打开页面,提示Register mipush appId or appKey is null or empty
问了官方人员,见这个帖子。https://ask.dcloud.net.cn/question/118126
我们分3步来分析可能会出什么问题。
第一步、引入lib:aps-release.aar和aps-unipush-release.aar
第二步、build配置key
第三步、工程的xml引入这个key
第一步,类库没有引入。
因为我的华为测试还好的,可以离线推送,所以我首先排除掉这个问题,我尝试把这两个类库去掉,安装好app,会提示push库不存在。
所以,排除掉这个问题。
第二步、build配置key
这步,似乎也没啥好看的,按照官方的离线打包文档,就是这么写的。
第三步、工程的xml引入这个key
后来读了push的安卓源代码。
发现是这步的问题,meta-data的位置放错了,要放到application后面,但奇怪的是华为的也在前面,不知道为什么能识别。
如果大家觉得受益匪浅的话,记得打赏一下哈。有问题加我QQ:13040