day114:MoFang:基于支付宝沙箱测试环境完成创建充值订单接口&服务端处理支付结果的同步通知和异步通知
MoFang充值流程图
服务端提供充值api接口,user/views.py
代码:
from application import jsonrpc from .models import Recharge from datetime import datetime from alipay import AliPay from alipay.utils import AliPayConfig import os, json, random from flask import current_app @jsonrpc.method("Recharge.create") @jwt_required # 验证jwt def create_recharge(money=10): """创建充值订单""" current_user_id = get_jwt_identity() user = User.query.get(current_user_id) if user is None: return { "errno": status.CODE_NO_USER, "errmsg": message.user_not_exists, } order_number = datetime.now().strftime("%y%m%d%H%M%S") + "%08d" % user.id + "%04d" % random.randint(0, 9999) recharge = Recharge( status=False, out_trade_number=order_number, name="账号充值-%s元" % money, user_id=user.id, money=money ) db.session.add(recharge) db.session.commit() # 创建支付宝sdk对象 app_private_key_string = open(os.path.join(current_app.BASE_DIR, "application/apps/users/keys/app_private_key.pem")).read() alipay_public_key_string = open(os.path.join(current_app.BASE_DIR, "application/apps/users/keys/app_public_key.pem")).read() alipay = AliPay( appid= current_app.config.get("ALIPAY_APP_ID"), app_notify_url=None, # 默认回调url app_private_key_string=app_private_key_string, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, alipay_public_key_string=alipay_public_key_string, sign_type=current_app.config.get("ALIPAY_SIGN_TYPE"), debug = False, # 默认False config = AliPayConfig(timeout=15) # 可选, 请求超时时间 ) order_string = alipay.api_alipay_trade_app_pay( out_trade_no=recharge.out_trade_number, # 订单号 total_amount=float(recharge.money), # 订单金额 subject=recharge.name, # 订单标题 notify_url=current_app.config.get("ALIPAY_NOTIFY_URL") # 服务端的地址,自定义一个视图函数给alipay ) return { "errno": status.CODE_OK, "errmsg": message.ok, "sandbox": current_app.config.get("ALIPAY_SANDBOX"), "order_string": order_string, "order_number": recharge.out_trade_number, }
# 支付宝配置信息 ALIPAY_APP_ID = "2016091600523592" ALIPAY_SIGN_TYPE = "RSA2" ALIPAY_NOTIFY_URL = "https://example.com/notify" ALIPAY_SANDBOX = True
<!DOCTYPE html> <html> <head> <title>用户中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> <script src="../static/js/socket.io.js"></script> </head> <body> <div class="app orchard" id="app"> <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png"> <div class="orchard-bg"> <img src="../static/images/bg2.png"> <img class="board_bg2" src="../static/images/board_bg2.png"> </div> <img class="back" @click="go_index" src="../static/images/user_back.png" alt=""> <div class="header"> <div class="info" @click="go_home"> <div class="avatar"> <img class="avatar_bf" src="../static/images/avatar_bf.png" alt=""> <img class="user_avatar" src="../static/images/avatar.png" alt=""> <img class="avatar_border" src="../static/images/avatar_border.png" alt=""> </div> <p class="user_name">好听的昵称</p> </div> <div class="wallet"> <div class="balance" @click="user_recharge"> <p class="title"><img src="../static/images/money.png" alt="">钱包</p> <p class="num">99,999.00</p> </div> <div class="balance"> <p class="title"><img src="../static/images/integral.png" alt="">果子</p> <p class="num">99,999.00</p> </div> </div> <div class="menu-list"> <div class="menu"> <img src="../static/images/menu1.png" alt=""> 排行榜 </div> <div class="menu"> <img src="../static/images/menu2.png" alt=""> 签到有礼 </div> <div class="menu" @click="go_orchard_shop"> <img src="../static/images/menu3.png" alt=""> 道具商城 </div> <div class="menu"> <img src="../static/images/menu4.png" alt=""> 邮件中心 </div> </div> </div> <div class="footer" > <ul class="menu-list"> <li class="menu">新手</li> <li class="menu">背包</li> <li class="menu-center" @click="go_orchard_shop">商店</li> <li class="menu">消息</li> <li class="menu">好友</li> </ul> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { music_play:true, namespace: '/mofang_orchard', token:"", socket: null, recharge_list: ['10','20','50','100','200','500','1000'], timeout: 0, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"orchard.html",params:{}}, } }, created(){ this.game.goFrame("orchard","my_orchard.html", this.current,{ x: 0, y: 180, w: 'auto', h: 'auto', },null); this.checkout(); }, methods:{ user_recharge(){ // 发起充值请求 api.actionSheet({ title: '余额充值', cancelTitle: '取消', buttons: this.recharge_list }, (ret, err)=>{ if( ret ){ if(ret.buttonIndex <= this.recharge_list.length){ // 充值金额 money = this.recharge_list[ret.buttonIndex-1]; // 调用支付宝充值 this.create_recharge(money); } }else{ } }); }, create_recharge(money){ // 获取历史信息记录 var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this, token, (new_access_token)=>{ this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "Recharge.create", "params": { "money": money, } },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ this.game.print(response.data); if(parseInt(response.data.result.errno)==1000){ // ***前往支付宝*** orderInfo = response.data.result.order_string; var aliPayPlus = api.require('aliPayPlus'); aliPayPlus.payOrder({ orderInfo: orderInfo, sandbox: true, // 将来APP上线需要修改成false }, (ret, err)=>{ this.game.print(ret,true); api.alert({ title: '支付结果', msg: ret.code, buttons: ['确定'] }); }); }else{ this.game.print(response.data); } }).catch(error=>{ // 网络等异常 this.game.print(error); }); }) }, checkout(){ var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this,token,(new_access_token)=>{ this.connect(); }); }, connect(){ // socket连接 this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']}); this.socket.on('connect', ()=>{ this.game.print("开始连接服务端"); }); }, go_index(){ this.game.outWin("orchard"); }, go_friends(){ this.game.goFrame("friends","friends.html",this.current); this.game.goFrame("friend_list","friend_list.html",this.current,{ x: 0, y: 190, w: 'auto', h: 'auto', },null,true); }, go_home(){ this.game.goWin("user","user.html", this.current); }, go_orchard_shop(){ // 种植园商店 this.game.goFrame("orchard_shop","shop.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); } } }); } </script> </body> </html>
因为我们使用的支付宝模块是第三方模块,所以在前面下载安装AppLoader里面是没有对应模块代码的,所以如果继续使用AppLoader进行模块功能使用,则会报错如下:
方式1: 在本地编辑器中选择
方式2: 在官网的用户后台中心生成自定义AppLoader
得到自定义AppLoader以后,在测试手机或者安卓模拟器中, 安装自定义AppLoader然后进行功能测试!
下载: https://sandbox.alipaydev.com/user/downloadApp.htm
客户端发起支付代码:
在实际过程中, 我们使用的正式的支付宝APP,所以在客户端中sandbox参数的值必须作为配置,引入.
<!DOCTYPE html> <html> <head> <title>用户中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> <script src="../static/js/socket.io.js"></script> </head> <body> <div class="app orchard" id="app"> <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png"> <div class="orchard-bg"> <img src="../static/images/bg2.png"> <img class="board_bg2" src="../static/images/board_bg2.png"> </div> <img class="back" @click="go_index" src="../static/images/user_back.png" alt=""> <div class="header"> <div class="info" @click="go_home"> <div class="avatar"> <img class="avatar_bf" src="../static/images/avatar_bf.png" alt=""> <img class="user_avatar" src="../static/images/avatar.png" alt=""> <img class="avatar_border" src="../static/images/avatar_border.png" alt=""> </div> <p class="user_name">好听的昵称</p> </div> <div class="wallet"> <div class="balance" @click="user_recharge"> <p class="title"><img src="../static/images/money.png" alt="">钱包</p> <p class="num">99,999.00</p> </div> <div class="balance"> <p class="title"><img src="../static/images/integral.png" alt="">果子</p> <p class="num">99,999.00</p> </div> </div> <div class="menu-list"> <div class="menu"> <img src="../static/images/menu1.png" alt=""> 排行榜 </div> <div class="menu"> <img src="../static/images/menu2.png" alt=""> 签到有礼 </div> <div class="menu" @click="go_orchard_shop"> <img src="../static/images/menu3.png" alt=""> 道具商城 </div> <div class="menu"> <img src="../static/images/menu4.png" alt=""> 邮件中心 </div> </div> </div> <div class="footer" > <ul class="menu-list"> <li class="menu">新手</li> <li class="menu">背包</li> <li class="menu-center" @click="go_orchard_shop">商店</li> <li class="menu">消息</li> <li class="menu">好友</li> </ul> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { music_play:true, namespace: '/mofang_orchard', token:"", socket: null, recharge_list: ['10','20','50','100','200','500','1000'], timeout: 0, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"orchard.html",params:{}}, } }, created(){ this.game.goFrame("orchard","my_orchard.html", this.current,{ x: 0, y: 180, w: 'auto', h: 'auto', },null); this.checkout(); }, methods:{ user_recharge(){ // 发起充值请求 api.actionSheet({ title: '余额充值', cancelTitle: '取消', buttons: this.recharge_list }, (ret, err)=>{ if( ret ){ if(ret.buttonIndex <= this.recharge_list.length){ // 充值金额 money = this.recharge_list[ret.buttonIndex-1]; // 调用支付宝充值 this.create_recharge(money); } }else{ } }); }, create_recharge(money){ // 获取历史信息记录 var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this, token, (new_access_token)=>{ this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "Recharge.create", "params": { "money": money, } },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ this.game.print(response.data); if(parseInt(response.data.result.errno)==1000){ // 前往支付宝 var aliPayPlus = api.require('aliPayPlus'); aliPayPlus.payOrder({ orderInfo: response.data.result.order_string, sandbox: response.data.result.sandbox, // 将来APP上线需要修改成false }, (ret, err)=>{ // ***增加充值成功失败的提醒*** pay_result = { 9000:"支付成功", 8000:"正在处理中", 4000:"订单支付失败", 5000:"重复请求", 6001:"取消支付", 6002:"网络连接出错", 6004:"支付结果未知", } api.alert({ title: '支付结果', msg: pay_result[ret.code], buttons: ['确定'] }); // 通知服务端, 修改充值结果 }); }else{ this.game.print(response.data); } }).catch(error=>{ // 网络等异常 this.game.print(error); }); }) }, checkout(){ var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this,token,(new_access_token)=>{ this.connect(); }); }, connect(){ // socket连接 this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']}); this.socket.on('connect', ()=>{ this.game.print("开始连接服务端"); }); }, go_index(){ this.game.outWin("orchard"); }, go_friends(){ this.game.goFrame("friends","friends.html",this.current); this.game.goFrame("friend_list","friend_list.html",this.current,{ x: 0, y: 190, w: 'auto', h: 'auto', },null,true); }, go_home(){ this.game.goWin("user","user.html", this.current); }, go_orchard_shop(){ // 种植园商店 this.game.goFrame("orchard_shop","shop.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); } } }); } </script> </body> </html>
from flask import request def notify_response(): """支付宝支付结果的异步通知处理""" data = request.form.to_dict() # sign 不能参与签名验证 signature = data.pop("sign") app_private_key_string = open(os.path.join(current_app.BASE_DIR, "application/apps/users/keys/app_private_key.pem")).read() alipay_public_key_string = open(os.path.join(current_app.BASE_DIR, "application/apps/users/keys/app_public_key.pem")).read() alipay = AliPay( appid= current_app.config.get("ALIPAY_APP_ID"), app_notify_url=None, # 默认回调url app_private_key_string=app_private_key_string, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, alipay_public_key_string=alipay_public_key_string, sign_type=current_app.config.get("ALIPAY_SIGN_TYPE"), debug = False, # 默认False config = AliPayConfig(timeout=15) # 可选, 请求超时时间 ) # verify success = alipay.verify(data, signature) if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED" ): """充值成功""" out_trade_number = data["out_trade_no"] recharge = Recharge.query.filter(Recharge.out_trade_number==out_trade_number).first() if recharge is None: return "fail" recharge.status=True user = User.query.get(recharge.user_id) if user is None: return "fail" user.money+=recharge.money db.session.commit() return "success" # 必须只能是success
from . import views from application.utils import path urlpatterns = [ .... path("/alipay/notify", views.notify_response), ]
所以需要改在utils/__init__.py
中路由绑定的path方法,代码:
def path(rule,func_view,**kwargs): # 把蓝图下视图和路由之间的映射关系处理成字典结构,方便后面注册蓝图的时候,直接传参 return {"rule":rule,"view_func":func_view,**kwargs}
from . import views from application.utils import path urlpatterns = [ .... path("/alipay/notify", views.notify_response,methods=["POST","GET"]), ]
完成上面的操作以后, 异步处理的视图方法就可以被外界使用POST请求访问了.
@jsonrpc.method("Recharge.return") @jwt_required # 验证jwt def return_recharge(out_trade_number): """同步通知处理""" current_user_id = get_jwt_identity() user = User.query.get(current_user_id) if user is None: return { "errno": status.CODE_NO_USER, "errmsg": message.user_not_exists, } recharge = Recharge.query.filter(Recharge.out_trade_number==out_trade_number).first() if recharge is None: return { "errno": status.CODE_RECHARGE_ERROR, "errmsg": message.recharge_not_exists, } recharge.status=True user.money+=recharge.money db.session.commit() return { "errno": status.CODE_OK, "errmsg": message.ok, "money": user.money, }
<!DOCTYPE html> <html> <head> <title>用户中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> <script src="../static/js/socket.io.js"></script> </head> <body> <div class="app orchard" id="app"> <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png"> <div class="orchard-bg"> <img src="../static/images/bg2.png"> <img class="board_bg2" src="../static/images/board_bg2.png"> </div> <img class="back" @click="go_index" src="../static/images/user_back.png" alt=""> <div class="header"> <div class="info" @click="go_home"> <div class="avatar"> <img class="avatar_bf" src="../static/images/avatar_bf.png" alt=""> <img class="user_avatar" src="../static/images/avatar.png" alt=""> <img class="avatar_border" src="../static/images/avatar_border.png" alt=""> </div> <p class="user_name">好听的昵称</p> </div> <div class="wallet"> <div class="balance" @click="user_recharge"> <p class="title"><img src="../static/images/money.png" alt="">钱包</p> <p class="num">{{money}}</p> </div> <div class="balance"> <p class="title"><img src="../static/images/integral.png" alt="">果子</p> <p class="num">99,999.00</p> </div> </div> <div class="menu-list"> <div class="menu"> <img src="../static/images/menu1.png" alt=""> 排行榜 </div> <div class="menu"> <img src="../static/images/menu2.png" alt=""> 签到有礼 </div> <div class="menu" @click="go_orchard_shop"> <img src="../static/images/menu3.png" alt=""> 道具商城 </div> <div class="menu"> <img src="../static/images/menu4.png" alt=""> 邮件中心 </div> </div> </div> <div class="footer" > <ul class="menu-list"> <li class="menu">新手</li> <li class="menu">背包</li> <li class="menu-center" @click="go_orchard_shop">商店</li> <li class="menu">消息</li> <li class="menu">好友</li> </ul> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { music_play:true, namespace: '/mofang_orchard', token:"", money:"", socket: null, recharge_list: ['10','20','50','100','200','500','1000'], timeout: 0, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"orchard.html",params:{}}, } }, created(){ this.game.goFrame("orchard","my_orchard.html", this.current,{ x: 0, y: 180, w: 'auto', h: 'auto', },null); this.checkout(); this.money = this.game.fget("money") }, methods:{ user_recharge(){ // 发起充值请求 api.actionSheet({ title: '余额充值', cancelTitle: '取消', buttons: this.recharge_list }, (ret, err)=>{ if( ret ){ if(ret.buttonIndex <= this.recharge_list.length){ // 充值金额 money = this.recharge_list[ret.buttonIndex-1]; // 调用支付宝充值 this.create_recharge(money); } }else{ } }); }, create_recharge(money){ // 获取历史信息记录 var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this, token, (new_access_token)=>{ this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "Recharge.create", "params": { "money": money, } },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ if(parseInt(response.data.result.errno)==1000){ // 前往支付宝 var aliPayPlus = api.require('aliPayPlus'); aliPayPlus.payOrder({ orderInfo: response.data.result.order_string, sandbox: response.data.result.sandbox, // 将来APP上线需要修改成false }, (ret, err)=>{ pay_result = { 9000:"支付成功", 8000:"正在处理中", 4000:"订单支付失败", 5000:"重复请求", 6001:"取消支付", 6002:"网络连接出错", 6004:"支付结果未知", } api.alert({ title: '支付结果', msg: pay_result[ret.code], buttons: ['确定'] }); // ***通知服务端, 修改充值结果*** this.return_recharge(response.data.result.order_number,token); }); }else{ this.game.print(response.data); } }).catch(error=>{ // 网络等异常 this.game.print(error); }); }) }, return_recharge(out_trade_number,token){ this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "Recharge.return", "params": { "out_trade_number": out_trade_number, } },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ if(parseInt(response.data.result.errno)==1000){ this.money = response.data.result.money.toFixed(2); } }) }, checkout(){ var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this,token,(new_access_token)=>{ this.connect(); }); }, connect(){ // socket连接 this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']}); this.socket.on('connect', ()=>{ this.game.print("开始连接服务端"); }); }, go_index(){ this.game.outWin("orchard"); }, go_friends(){ this.game.goFrame("friends","friends.html",this.current); this.game.goFrame("friend_list","friend_list.html",this.current,{ x: 0, y: 190, w: 'auto', h: 'auto', },null,true); }, go_home(){ this.game.goWin("user","user.html", this.current); }, go_orchard_shop(){ // 种植园商店 this.game.goFrame("orchard_shop","shop.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); } } }); } </script> </body> </html>
@jsonrpc.method("User.login") def login(ticket,randstr,account,password): """根据用户登录信息生成token""" # 校验防水墙验证码 params = { "aid": current_app.config.get("CAPTCHA_APP_ID"), "AppSecretKey": current_app.config.get("CAPTCHA_APP_SECRET_KEY"), "Ticket": ticket, "Randstr": randstr, "UserIP": request.remote_addr } # 把字典数据转换成地址栏的查询字符串格式 # aid=xxx&AppSecretKey=xxx&xxxxx params = urlencode(params) url = current_app.config.get("CAPTCHA_GATEWAY") # 发送http的get请求 f = urlopen("%s?%s" % (url, params)) # https://ssl.captcha.qq.com/ticket/verify?aid=xxx&AppSecretKey=xxx&xxxxx content = f.read() res = json.loads(content) print(res) if int(res.get("response")) != 1: # 验证失败 return {"errno": status.CODE_CAPTCHA_ERROR, "errmsg": message.captcaht_no_match} # 1. 根据账户信息和密码获取用户 if len(account) < 1: return {"errno":status.CODE_NO_ACCOUNT,"errmsg":message.account_no_data} user = User.query.filter(or_( User.mobile==account, User.email==account, User.name==account )).first() if user is None: return {"errno": status.CODE_NO_USER,"errmsg":message.user_not_exists} # 验证密码 if not user.check_password(password): return {"errno": status.CODE_PASSWORD_ERROR, "errmsg":message.password_error} # 2. 生成jwt token access_token = create_access_token(identity=user.id) refresh_token = create_refresh_token(identity=user.id) print(access_token) print(refresh_token) return { "errno": status.CODE_OK, "errmsg": message.ok, "id": user.id, "nickname": user.nickname if user.nickname else account, "avatar": user.avatar if user.avatar else current_app.config["DEFAULT_AVATAR"], "money": float(user.money), "credit": float(user.credit), "access_token": access_token, "refresh_token":refresh_token }
<!DOCTYPE html> <html> <head> <title>用户中心</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta charset="utf-8"> <link rel="stylesheet" href="../static/css/main.css"> <script src="../static/js/vue.js"></script> <script src="../static/js/axios.js"></script> <script src="../static/js/main.js"></script> <script src="../static/js/uuid.js"></script> <script src="../static/js/settings.js"></script> <script src="../static/js/socket.io.js"></script> </head> <body> <div class="app orchard" id="app"> <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png"> <div class="orchard-bg"> <img src="../static/images/bg2.png"> <img class="board_bg2" src="../static/images/board_bg2.png"> </div> <img class="back" @click="go_index" src="../static/images/user_back.png" alt=""> <div class="header"> <div class="info" @click="go_home"> <div class="avatar"> <img class="avatar_bf" src="../static/images/avatar_bf.png" alt=""> <img class="user_avatar" src="../static/images/avatar.png" alt=""> <img class="avatar_border" src="../static/images/avatar_border.png" alt=""> </div> <p class="user_name">好听的昵称</p> </div> <div class="wallet"> <div class="balance" @click="user_recharge"> <p class="title"><img src="../static/images/money.png" alt="">钱包</p> <p class="num">{{money}}</p> </div> <div class="balance"> <p class="title"><img src="../static/images/integral.png" alt="">果子</p> <p class="num">99,999.00</p> </div> </div> <div class="menu-list"> <div class="menu"> <img src="../static/images/menu1.png" alt=""> 排行榜 </div> <div class="menu"> <img src="../static/images/menu2.png" alt=""> 签到有礼 </div> <div class="menu" @click="go_orchard_shop"> <img src="../static/images/menu3.png" alt=""> 道具商城 </div> <div class="menu"> <img src="../static/images/menu4.png" alt=""> 邮件中心 </div> </div> </div> <div class="footer" > <ul class="menu-list"> <li class="menu">新手</li> <li class="menu">背包</li> <li class="menu-center" @click="go_orchard_shop">商店</li> <li class="menu">消息</li> <li class="menu">好友</li> </ul> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { music_play:true, namespace: '/mofang_orchard', token:"", money:"", socket: null, recharge_list: ['10','20','50','100','200','500','1000'], timeout: 0, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"orchard.html",params:{}}, } }, created(){ this.game.goFrame("orchard","my_orchard.html", this.current,{ x: 0, y: 180, w: 'auto', h: 410, },null); this.checkout(); this.money = this.game.fget("money") }, methods:{ user_recharge(){ // 发起充值请求 api.actionSheet({ title: '余额充值', cancelTitle: '取消', buttons: this.recharge_list }, (ret, err)=>{ if( ret ){ if(ret.buttonIndex <= this.recharge_list.length){ // 充值金额 money = this.recharge_list[ret.buttonIndex-1]; // 调用支付宝充值 this.create_recharge(money); } }else{ } }); }, create_recharge(money){ // 获取历史信息记录 var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this, token, (new_access_token)=>{ this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "Recharge.create", "params": { "money": money, } },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ if(parseInt(response.data.result.errno)==1000){ // 前往支付宝 var aliPayPlus = api.require('aliPayPlus'); aliPayPlus.payOrder({ orderInfo: response.data.result.order_string, sandbox: response.data.result.sandbox, // 将来APP上线需要修改成false }, (ret, err)=>{ pay_result = { 9000:"支付成功", 8000:"正在处理中", 4000:"订单支付失败", 5000:"重复请求", 6001:"取消支付", 6002:"网络连接出错", 6004:"支付结果未知", } api.alert({ title: '支付结果', msg: pay_result[ret.code], buttons: ['确定'] }); // 通知服务端, 修改充值结果 this.return_recharge(response.data.result.order_number,token); }); }else{ this.game.print(response.data); } }).catch(error=>{ // 网络等异常 this.game.print(error); }); }) }, return_recharge(out_trade_number,token){ this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "Recharge.return", "params": { "out_trade_number": out_trade_number, } },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ if(parseInt(response.data.result.errno)==1000){ this.money = response.data.result.money.toFixed(2); } }) }, checkout(){ var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this,token,(new_access_token)=>{ this.connect(); }); }, connect(){ // socket连接 this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']}); this.socket.on('connect', ()=>{ this.game.print("开始连接服务端"); }); }, go_index(){ this.game.outWin("orchard"); }, go_friends(){ this.game.goFrame("friends","friends.html",this.current); this.game.goFrame("friend_list","friend_list.html",this.current,{ x: 0, y: 190, w: 'auto', h: 'auto', },null,true); }, go_home(){ this.game.goWin("user","user.html", this.current); }, go_orchard_shop(){ // 种植园商店 this.game.goFrame("orchard_shop","shop.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); } } }); } </script> </body> </html>
.orchard-frame .prop-list{ position: absolute; bottom: 1rem; /*bottom: 6rem 修改成 bottom: 1rem*/ width: 100%; } .orchard-frame .pet-hp-list{ position: absolute; right: 0; bottom: 3rem;/*bottom: 8rem 修改成 bottom: 3rem*/ width: 11rem; height: 4rem; }