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; }