支付宝小程序云开发是基于 Serverless 的一站式小程序后端服务开发平台,支持动态扩缩容低投入,前后端一体化高效研发,简化开发流程,提高研发效率。
● 单一技术栈:前端为 Js语言,云开发后端采用 NodeJS,前后端统一技术栈,便于全栈研发。
● IDE 内一栈式开发:小程序的前后端 开发、测试、发布、部署都可以在 IDE 端中完成,免登陆、免鉴权。
● 免域名注册备案:小程序前端 SDK 直接调用 Function,无需域名注册备案,方便使用。
● 按需付费动态扩容。
● 纯业务开发告别框架技术学习成本,提高上手效率。
方式一IDEA版操作台、打开支付宝小程序开发工具进入项目,点击右上角云开,新建一个云环境,目前云环境有免费版本对于初学者来说,练手足够了!!!
方式二网页版操作台、登录支付宝开发者平台进入控制台搜索找到云开发,新建一个云环境,开发者平台控制台地址已放下面:
https://cloudbase.cloud.alipay.com/console
下面以网页版操作台为例
此处有一个默认的域名作为接口路由,这个是我们调用云函数是否成功的一个关键。注意小程序如果上线需要在这个地方配置一个已经备案好,并且有SSL证书可以开启HTTPS服务的域名。
环境管理中的云调用将接口服务开启,并添加接口权限。我们以用户授权登录为例,添加接口“alipay.system.oauth.token”。注意添加接口前必须要在支付宝开放平台的产品中先添加产品。我们以登录为例:开通“获取会员信息”产品
新建一个NoSQL数据库的集合名称。我们依然以登录为例,存储用户信息。新建一个"userInfo"集合,并设置一个索引值_id,选择升序方式。
根目录下:mini.project文件
{
"format": 2,
"compileOptions": {
"component2": true
},
"miniprogramRoot": "./miniprogram",
"cloudbaseRoot": "cloud" //云函数目录
}
支付宝小程序目前所有的云服务业务流程都是基于云函数调用的方式(这一点还是跟微信小程序不一样的一点,微信小程序除了云函数还可以在pages目录下的页面js文件中编写云开发API)。
我们依然以登录案例作为线索,在IDEA中新建一个云函数addUserInfo,用来上传用户信息到云数据库userInfo当中。
我们可以在index.js当中编写云函数代码。到此处返回网页端云环境,点击云函数,你就可以看见你所创建的所有云函数。并且可以点击每个云函数进行更详细的配置,自己浏览编辑云函数代码。以及进行云函数的发布与版本更新。
<view a:if="{{ loginFlag==true }}">
<view class="topBox">
<view class="topBgc">
<image class="face" src="{{face}}" />
<view style="margin-top:30rpx;color:white;font-weight:550">
{{userName}}
view>
view>
<view class="be_a_Runner">
<image mode="widthFix" style="width:100%;position:relative;z-index:0;top:0;left:0" src="/image/lwhvipbgc.png" />
<view class="toBe">
<view style="line-height:150rpx;margin-left:70rpx;color:wheat;font-size:40rpx;font-weight:550;width:50%">
认证为跑者
view>
<view style="width:50%;display:flex;align-items:center">
<view class="renzheng" onTap="renzheng" data-id="{{userId}}">
立即认证
view>
view>
view>
view>
view>
<view class="mine">
<view>
<view>
<image style="width:100rpx;height:100rpx" src="/image/lwhdetal.png" />
view>
<view>
食堂订单
view>
view>
<view style="border-left:1rpx solid rgb(200,200,200);border-right:1rpx solid rgb(200,200,200)">
<view>
<image style="width:100rpx;height:100rpx" src="/image/shopNav.png" />
view>
<view>
二手订单
view>
view>
<view style="border-right:1rpx solid rgb(200,200,200)">
<view>
<image style="width:100rpx;height:100rpx" src="/image/schoolAc.png" />
view>
<view>
校园活动
view>
view>
<view>
<view>
<image style="width:100rpx;height:100rpx" src="/image/order01.png" />
view>
<view>
我的跑腿
view>
view>
view>
<view class="settings">
<view class="settingItem">
<view style="width:14rpx;height:40rpx;background-color:#389ef5;margin-right:20rpx">view>
<text style="width:90%">设置text>
<image style="width:40rpx;height:40rpx" src="/image/lwhmore.png" />
view>
<view class="settingItem">
<view style="width:14rpx;height:40rpx;background-color:#389ef5;margin-right:20rpx">view>
<text style="width:90%">客服中心text>
<image style="width:40rpx;height:40rpx" src="/image/lwhmore.png" />
view>
<view class="settingItem">
<view style="width:14rpx;height:40rpx;background-color:#389ef5;margin-right:20rpx">view>
<text style="width:90%">我的地址text>
<image style="width:40rpx;height:40rpx" src="/image/lwhmore.png" />
view>
<view class="settingItem">
<view style="width:14rpx;height:40rpx;background-color:#389ef5;margin-right:20rpx">view>
<text style="width:90%">退出登录text>
<image style="width:40rpx;height:40rpx" src="/image/lwhmore.png" />
view>
view>
view>
<view a:if="{{ loginFlag==false}}">
<view style="width:100%;height:150rpx">
view>
<view class="login_photo">
<image src="https://636c-cloud1-4gsna3lu4fd8e5fb-1313325135.tcb.qcloud.la/xpblog/IMG_5104.PNG?sign=dba60d02dcb7cd6fec1aa3b12b7bf891&t=1677937533">image>
view>
<view class="login_txt">
<view class="txt_row01" style="font-size: 40rpx;">扫榻以待view>
<view class="txt_row02">view>
<view class="txt_row03" style="color: rgb(107, 107, 107);font-size: 28rpx;">让生活更便捷,让大学更丰富view>
view>
<button open-type="getAuthorize" scope="userInfo"
onGetAuthorize="getOpenUserInfo"
onError="handleAuthError"
style="width:70%;margin:40rpx auto"
class="login"
>登录button>
view>
<view class="loginging" a:if="{{ logining==true }}">
view>
page{
background-color: rgb(247, 247, 247);
}
.topBox{
width: 100%;
height: 520rpx;
background-image: linear-gradient( 180deg, #ffffff 0%, #9ed5fc 50%,#49d2f8 100%);
}
.topBgc{
display:flex;
flex-direction:column;
width:100%;
justify-content:center;
align-items:center;
padding-top:140rpx;
}
.face{
width:180rpx;
height:180rpx;
border-radius:50%;
border:solid 16rpx rgba(255, 255, 255, 0.925);
}
/* 成为跑者 */
.be_a_Runner{
margin-top: 30rpx;
position: relative;
width: 90%;
margin-left: 5%;
height: 150rpx;
border-radius: 50rpx;
overflow: hidden;
box-shadow: 0 2rpx 8rpx rgba(91, 203, 247, 0.798);
}
.toBe{
position:absolute;
top:0;left:0;z-index:1;
display:flex;
flex-direction: row;
width: 100%;
}
/* 认证按钮 */
.renzheng{
font-weight:600;
color:white;
background-color:rgb(246, 217, 52);
border-radius:50rpx;
overflow:hidden;
line-height:90rpx;
width:200rpx;
text-align:center;
margin-left: 60rpx;
}
.mine{
width: 90%;
margin-left: 5%;
margin-top: 100rpx;
/* height: 120rpx; */
display: flex;
flex-direction: row;
border-radius: 20rpx;
overflow: hidden;
background-color: rgb(249, 252, 253);
/* box-shadow: 0 3rpx 5rpx rgba(38, 187, 245, 0.798); */
padding-bottom: 30rpx;
}
.mine>view{
margin-top: 30rpx;
width: 33.33333%;
text-align: center;
line-height: 40rpx;
color: #303030;
font-size: 30rpx;
font-weight: 500;
}
.settings{
margin-top: 30rpx;
width: 90%;
margin-left: 5%;
}
.settingItem{
background-color: rgb(250, 254, 255);
line-height: 50rpx;
padding: 30rpx;
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 20rpx;
border-radius: 15rpx;
/* box-shadow: 0 2rpx 8rpx #5bcbf7b1; */
}
.login_photo{
width: 100%;
}
.login_photo>image{
width: 100%;
}
.login_txt{
display: flex;
flex-direction: column;
justify-content: left;
margin-left: 80rpx;
margin-top: 100rpx;
}
.login_txt>view{
margin-bottom: 20rpx;
}
.txt_row02{
width: 200rpx;
height: 10rpx;
border-radius: 30rpx;
background:-webkit-linear-gradient(left,rgb(92,104,206),rgb(171,179,241),white);
}
.login{
background-color: rgb(92, 104, 206);
border-radius: 50rpx;
color: white;
margin-top: 100rpx;
}
/* 登陆中 */
.loginging{
width: 100%;
height: 100vh;
position: fixed;
z-index: 999;
background-color: black;
opacity: 0.4;
top: 0;
}
##js文件
Page({
data: {
shitang:"3", //食堂订单
ershou:"6", //二手
active:"8", //活动
run:"10", //跑腿
userId:"",
userName:"",
face:"",
loginFlag:false,
canIUseAuthButton: my.canIUse('button.open-type.getAuthorize'),
formattedDateTime:'',
loginUserInfo:'',
logining:false
},
onLoad(){
/* 登录标志 */
try{
console.log(my.getStorageSync({key:"userInfo"}));
let userInfo=my.getStorageSync({key:"userInfo"})
if(userInfo.data){
this.setData({
loginFlag:true,
userName:userInfo.data.userName,
face:userInfo.data.avatar
})
}
}catch(error){
my.showModal({
title:'您似乎还未登录,确定登录?',
success:(res)=>{
if(res.confirm){
my.switchTab({
url:"/pages/user/user"
})
}
}
})
}
},
/* 登录按钮 */
getOpenUserInfo(){
const self=this
//判断新老用户
self.setData({
logining:true
})
my.showLoading({
content:'身份鉴别中'
})
my.fncontext.callFunction({
name:"queryNoCondition",
data:{
coll:"userInfo",
},success:(userinfo)=>{
my.hideLoading({})
console.log("新老用户返回数据",userinfo);
if(userinfo.result.length!=0){
self.oldUser(userinfo.result[0].username,userinfo.result[0].avatar,userinfo.result[0]._openid)
}else{
self.NewUser({})
}
},fail:(userinfo)=>{
my.hideLoading({})
console.log("新老用户返回数据错误",userinfo);
}
})
},
/* 获取当前的时间 */
getNowTime(){
// 获取当前日期和时间
var now = new Date();
// 格式化年份
var year = now.getFullYear();
// 格式化月份,JavaScript中月份是从0开始的,所以要加1
var month = now.getMonth() + 1;
month = month < 10 ? '0' + month : month; // 添加前导零
// 格式化日期
var date = now.getDate();
date = date < 10 ? '0' + date : date; // 添加前导零
// 格式化小时
var hours = now.getHours();
hours = hours < 10 ? '0' + hours : hours; // 添加前导零
// 格式化分钟
var minutes = now.getMinutes();
minutes = minutes < 10 ? '0' + minutes : minutes; // 添加前导零
// 组合最终的日期时间字符串
var formattedDateTime = year + '-' + month + '-' + date + ' ' + hours + ':' + minutes;
// 输出或保存格式化后的日期时间
console.log(formattedDateTime);
this.setData({
formattedDateTime:formattedDateTime
})
},
//新老用户判断
oldUser(name,avatar,openid){
const self=this
self.setData({
logining:false
})
var userInfoTemp={}
userInfoTemp.userName=name
userInfoTemp.avatar=avatar
userInfoTemp.openid=openid
my.setStorageSync({
data:userInfoTemp,
key:'userInfo'
})
my.reLaunch({
url:"/pages/user/user"
})
},
NewUser(){
const self=this
self.getNowTime({})
my.getAuthCode({
success:(res)=>{
//console.log("authCode",res);
let authCode=res.authCode
my.showLoading({
content:'新用户,注册中'
})
//动态令牌换取userid||openid
my.fncontext.callFunction({
name:'userID',
data:{
auth_code:authCode
},success:(userid)=>{
//console.log(userid);
const openidTemp=userid.result.open_id
my.getOpenUserInfo({
success: (info) => {
// console.log(info);
console.log(self.data.formattedDateTime);
const userInfo = JSON.parse(info.response).response
my.fncontext.callFunction({
name:"noSqlAdd",
data:{
openid:userid.result.open_id,
username:userInfo.nickName,
avatar:userInfo.avatar,
registerTime:self.data.formattedDateTime
},
success:(e)=>{
my.hideLoading({})
console.log("注册成功,返回信息:",e);
//缓存到本地
var userInfoTemp={}
userInfoTemp.userName=userInfo.nickName
userInfoTemp.avatar=userInfo.avatar
userInfoTemp.openid=openidTemp
my.setStorageSync({
data:userInfoTemp,
key:'userInfo'
})
self.setData({
logining:false
})
my.reLaunch({
url:"/pages/user/user"
})
},fail:(e)=>{
self.setData({
logining:false
})
console.log("注册失败,错误:",e);
my.hideLoading({})
}
})
},
fail: (err) => {
self.setData({
logining:false
})
console.log(err)
}
});
}
})
}
})
}
});
const cloud = require('@alipay/faas-server-sdk');
exports.main = async (event, context) => {
const db=cloud.database();
db.collection("userInfo").add({
data:{
openid:event.openid,
username:event.username,
avatar:event.avatar,
registerTime:event.registerTime
},success:(res)=>{
return res
},fail:(error)=>{
return error
}
})
};
const cloud = require('@alipay/faas-server-sdk');
exports.main = async (event, context) => {
const db = cloud.database();
const coll=event.coll
return await db.collection(coll).where({
_openid: cloud.getAlipayContext().OPENID
}).get({})
};