day115:MoFang:种植园我的背包&种植园道具购买
目录
1.我的背包
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!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" @click="go_my_package">背包</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 }); }, go_my_package(){ // 我的背包 this.game.goFrame("package","package.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); }, } }); } </script> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!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> </head> <body> <div class="app frame avatar add_friend package" id="app"> <div class="box"> <p class="title">我的背包</p> <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt=""> <div class="prop_list"> <div class="item"> <img src="../static/images/fruit_tree.png" alt=""> <span>10</span> </div> <div class="item"> <img src="../static/images/prop1.png" alt=""> <span>10</span> </div> <div class="item"></div> <div class="item"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> <div class="item lock"></div> </div> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { user_id: "", // 当前登陆用户Id prev:{name:"",url:"",params:{}}, current:{name:"package",url:"package.html",params:{}}, } }, created(){ this.user_id = this.game.get("id") || this.game.fget("id"); }, methods:{ close_frame(){ this.game.outFrame("package"); }, } }); } </script> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
.package .prop_list{ position: absolute; left: 4.2rem; top: 10rem; width: 21rem; height: 39.8rem; overflow: scroll; } .package .prop_list .item{ background: #a63600; border: 3px solid #ff9900; width: 4rem; height: 4rem; margin: .2rem; float: left; border-radius: 5px; position: relative; } .package .prop_list .item img{ position: absolute; margin: auto; width: 3rem; height: 3rem; top: 0; bottom: 0; left: 0; right: 0; } .package .prop_list .item span{ font-size: 1.5rem; color: #fff; position: absolute; bottom: 0; right: 0; } .package .prop_list .lock:after{ display: block; content:"x"; font-size: 4rem; color: #ff9900; text-align: center; line-height: 100%; height: 4rem; width: 4rem; }
所以需要在实现商品购买以后, 还需要把参数保存到数据库中.
为参数信息设计表结构,orchard/models.py
代码:
class Setting(BaseModel): """参数信息""" __tablename__ = "mf_orchard_setting" title=db.Column(db.String(255), comment="提示文本") value=db.Column(db.String(255), comment="数值")
orchard/models.py
, 代码:
from application.utils.models import BaseModel,db class Goods(BaseModel): """商品基本信息""" __tablename__ = "mf_goods" remark = db.Column(db.String(255), comment="商品描述") price = db.Column(db.Numeric(7,2), comment="商品价格[余额]") credit = db.Column(db.Integer, comment="商品价格[果子]") image = db.Column(db.String(255), comment="商品图片")
index.html
,修改go_orchard方法的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <title>首页</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta name="format-detection" content="telephone=no,email=no,date=no,address=no"> <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> </head> <body> <div class="app" id="app"> <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png"> <div class="bg"> <img src="../static/images/bg0.jpg"> </div> <ul> <li><img class="module1" @click="go_orchard" src="../static/images/image1.png"></li> <li><img class="module2" @click="go_home" src="../static/images/image2.png"></li> <li><img class="module3" src="../static/images/image3.png"></li> <li><img class="module4" src="../static/images/image4.png"></li> </ul> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { music_play:true, // 默认播放背景音乐 prev:{name:"",url:"",params:{}}, // 上一页状态 current:{name:"index",url:"index.html","params":{}}, // 下一页状态 } }, watch:{ music_play(){ if(this.music_play){ this.game.play_music("../static/mp3/bg1.mp3"); }else{ this.game.stop_music(); } } }, created(){ this.app_listener(); this.check_user_login(); }, methods:{ app_listener(){ // 使用appintenr监听并使用appParam接收URLScheme的参数 // 收集操作保存起来,并跳转到注册页面. // 注册frame中, 用户注册成功以后,记录邀请信息. api.addEventListener({ name:'appintent' // 当前事件监听必须是唯一的,整个APP中只能编写一次,否则冲突导致监听无效 },(ret,err)=>{ var appParam = ret.appParam; this.game.print(typeof appParam); // {"uid":"15"} // 保存URLScheme参数到本地 this.game.fsave(appParam); // 跳转到注册页面 this.game.goWin("user","register.html", this.current); }); }, check_user_login(){ let token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this, token, (new_access_token)=>{ if(new_access_token.errno == 1005){ this.game.save({"access_token":""}); this.game.fremove("access_token"); } }); }, go_home(){ if(this.game.get("access_token") || this.game.fget("access_token")){ this.game.goWin("user","user.html", this.current); }else{ this.game.goWin("user","login.html", this.current); } }, go_orchard(){ if(this.game.get("access_token") || this.game.fget("access_token")){ this.game.goWin("orchard","orchard.html", this.current,reload=false); }else{ this.game.goWin("user","login.html", this.current); } } } }) } </script> </body> </html>
2.orchard.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!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" @click="go_my_package">背包</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', 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.goWin("root"); }, 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 }); }, go_my_package(){ // 我的背包 this.game.goFrame("package","package.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); }, } }); } </script> </body> </html>
3.main.js
goWin(name,url,pageParam,reload=true){ // 新建窗口 api.openWin({ name: name, // 自定义窗口名称 bounces: false, // 窗口是否上下拉动 reload: reload, // 如果页面已经在之前被打开了,是否要重新加载当前窗口中的页面 useWKWebView:true, historyGestureEnabled:true, url: url, // 窗口创建时展示的html页面的本地路径[相对于当前代码所在文件的路径] animation:{ // 打开新建窗口时的过渡动画效果 type: "push", //动画类型(详见动画类型常量) subType: "from_right", //动画子类型(详见动画子类型常量) duration:300 //动画过渡时间,默认300毫秒 }, pageParam: pageParam // 传递给下一个窗口使用的参数.将来可以在新窗口中通过 api.pageParam.name 获取 }); }
2.道具购买
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!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> </head> <body> <div class="app frame avatar update_nickname add_friend shop" id="app"> <div class="box"> <p class="title">商店</p> <img class="close" @click="close_frame" src="../static/images/close_btn1.png" alt=""> <div class="friends_list shop_list"> <div class="item" @click="buy_prop(goods.id)" v-for="goods in goods_list"> <div class="avatar shop_item"> <img :src="settings.static_url+goods.image" alt=""> </div> <div class="info"> <p class="username">{{goods.name}}</p> <p class="time">{{goods.remark}}</p> </div> <div class="status">{{goods.price}}</div> </div> </div> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { user_id: "", // 当前登陆用户Id goods_list:[], // 商品列表 page: 1, limit: 10, is_send_ajax:false, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"shop.html",params:{}}, } }, created(){ this.user_id = this.game.get("id") || this.game.fget("id"); this.get_goods_list(); }, methods:{ close_frame(){ this.game.outFrame("orchard_shop"); }, get_goods_list(){ if(this.is_send_ajax){ return ; } // 通过请求获取当前用户的好友列表 var token = this.game.get("access_token") || this.game.fget("access_token"); this.game.checkout(this, token, (new_access_token)=>{ this.is_send_ajax = true; this.axios.post("",{ "jsonrpc": "2.0", "id": this.uuid(), "method": "Orchard.goods.list", "params": { "page": this.page, "limit": this.limit, } },{ headers:{ Authorization: "jwt " + token, } }).then(response=>{ if(parseInt(response.data.result.errno)==1000){ if(this.page+1 == response.data.result.pages){ this.is_send_ajax = true; }else{ this.is_send_ajax = false; this.page+=1; } if(this.page>1){ api.refreshHeaderLoadDone(); } this.goods_list = response.data.result.goods_list.concat(this.goods_list); }else if(parseInt(response.data.result.errno) == 1008){ this.friends = []; }else{ this.game.print(response.data); } }).catch(error=>{ // 网络等异常 this.game.print(error); }); }) }, buy_prop(prop_id){ // 购买商品道具 // 让用户选择购买的数量 api.prompt({ text: 1, title:"请输入购买数量", type: "number", buttons: ['确定', '取消'] }, (ret, err)=>{ if(ret.buttonIndex == 1){ // 通过通知告知socket进行商品购买 api.sendEvent({ name: 'buy_prop', extra: { "pid": prop_id, "num": ret.text } }); } }); } } }); } </script> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!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/jAs/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" @click="go_my_package">背包</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', 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"); this.buy_prop(); }, 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("开始连接服务端"); var id = this.game.fget("id"); this.socket.emit("login",{"uid":id}); }); }, go_index(){ this.game.goWin("root"); }, 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 }); }, go_my_package(){ // 我的背包 this.game.goFrame("package","package.html", this.current,null,{ type:"push", subType:"from_top", duration:300 }); }, buy_prop(){ api.addEventListener({ name: 'buy_prop' }, (ret, err)=>{ if( ret ){ // 用户购买道具 this.socket.emit("user_buy_prop",ret.value); } }); }, } }); } </script> </body> </html>
from application import socketio from flask import request from application.apps.users.models import User from flask_socketio import join_room, leave_room from application import mongo from .models import Goods from status import APIStatus as status from message import ErrorMessage as errmsg # 断开socket通信 @socketio.on("disconnect", namespace="/mofang") def user_disconnect(): print("用户%s退出了种植园" % request.sid ) @socketio.on("login", namespace="/mofang") def user_login(data): # 分配房间 room = data["uid"] join_room(room) # 保存当前用户和sid的绑定关系 # 判断当前用户是否在mongo中有记录 query = { "_id": data["uid"] } ret = mongo.db.user_info_list.find_one(query) if ret: mongo.db.user_info_list.update_one(query,{"$set":{"sid": request.sid}}) else: mongo.db.user_info_list.insert_one({ "_id": data["uid"], "sid": request.sid, }) socketio.emit("login_response", {"errno":status.CODE_OK,"errmsg":errmsg.ok}, namespace="/mofang", room=room)
@socketio.on("user_buy_prop", namespace="/mofang") def user_buy_prop(data): """用户购买道具""" room = request.sid # 从mongo中获取当前用户信息 # 1.获取当前sid对应的mongo存储的字典:包括_id,sid,prop_list user_info = mongo.db.user_info_list.find_one({"sid":request.sid}) # 2.根据mongo存储的字典get取键获取当前用户id user = User.query.get(user_info.get("_id")) # 3.判断当前用户是否存在 if user is None: socketio.emit("user_buy_prop_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room) return # 从mysql中获取商品价格 # 4.通过商品id查询出当前商品model对象 prop = Goods.query.get(data["pid"]) # 5.判断用户余额是否充足 if float(user.money) < float(prop.price) * int(data["num"]): socketio.emit("user_buy_prop_response", {"errno":status.CODE_NO_MONEY,"errmsg":errmsg.money_no_enough}, namespace="/mofang", room=room) return # 从mongo中获取用户列表信息,提取购买的商品数量进行累加和余额 query = {"sid": request.sid} if user_info.get("prop_list") is None: # 别忘了,user_info是mongo字典 """此前没有购买任何道具""" message = {"$set":{"prop_list":{"prop_%s" % prop.id:int(data["num"])}}} mongo.db.user_info_list.update_one(query,message) else: """此前有购买了道具""" prop_list = user_info.get("prop_list") # 道具列表 if ("prop_%s" % prop.id) in prop_list: """如果再次同一款道具""" prop_list[("prop_%s" % prop.id)] = prop_list[("prop_%s" % prop.id)] + int(data["num"]) else: """此前没有购买过这种道具""" prop_list[("prop_%s" % prop.id)] = int(data["num"]) mongo.db.user_info_list.update_one(query, {"$set":{"prop_list":prop_list}}) socketio.emit("user_buy_prop_response", {"errno":status.CODE_OK,"errmsg":errmsg.ok}, namespace="/mofang", room=room)
4.种植园道具购买流程图