day117:MoFang:宠物栏的功能实现&宠物道具的使用
1. 宠物的显示
2. 宠物的使用
3. 宠物的饱食度
4. 宠物的开锁
import math from application import redis @socketio.on("pet_show", namespace="/mofang") def pet_show(): """显示宠物""" room = request.sid user_info = mongo.db.user_info_list.find_one({"sid":request.sid}) user = User.query.get(user_info.get("_id")) if user is None: socketio.emit("pet_show_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room) return # 1.获取宠物列表 pet_list = user_info.get("pet_list", []) """ pet_list: [ { "pid":11, "image":"pet.png", "hp":100%, "created_time":xxxx-xx-xx xx:xx:xx, "skill":"70%", "has_time":30天 }, ] """ # 2.从redis中提取当前宠物的饱食度和有效期 for key,pet in enumerate(pet_list): pet["hp"] = math.ceil( redis.ttl("pet_%s_%s_hp" % (user.id,key+1)) / 86400 * 100 ) pet["has_time"] = redis.ttl("pet_%s_%s_expire" % (user.id,key+1)) pet_number = user_info.get("pet_number", 1) socketio.emit( "pet_show_response", { "errno": status.CODE_OK, "errmsg": errmsg.ok, "pet_list": pet_list, "pet_number": pet_number, }, namespace="/mofang", room=room )
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (11, 'pet_expire_2', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '1号宠物的有效期', '30'); INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (12, 'pet_skill_2', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '1号宠物的防御概率', '50'); INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (13, 'pet_expire_3', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '2号宠物的有效期', '30'); INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (14, 'pet_skill_3', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '2号宠物的防御概率', '20'); INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (15, 'pet_expire_4', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '3号宠物的有效期', '30'); INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (16, 'pet_skill_4', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '3号宠物的防御概率', '70'); INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (17, 'pet_expire_5', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '4号宠物的有效期', '30'); INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (18, 'pet_skill_5', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '4号宠物的防御概率', '30');
<!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:"", settings_info:{ orchard: {}, // 种植园公共参数 user:{}, // 用户私有相关参数 }, socket: null, recharge_list: ['10','20','50','100','200','500','1000'], timeout: 0, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"orchard.html",params:{}}, } }, beforeCreate(){ this.game.goFrame("orchard","my_orchard.html", this.current,{ x: 0, y: 180, w: 'auto', h: 410, },null); }, created(){ 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(); this.login(); this.user_package(); this.buy_prop(); this.unlock_package_number(); this.show_pet(); }); }, 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}); this.socket.emit("user_prop"); }); }, login(){ this.socket.on("login_response",(message)=>{ this.settings_info.orchard = message.orchard_settings; this.settings_info.user=message.user_settings; this.game.fsave({ "orchard_settings":message.orchard_settings, "user_settings":message.user_settings }); }); }, user_package(){ // 用户背包道具列表 this.socket.on("user_prop_response",(message)=>{ this.game.fsave({ "user_package":message.data, }) }) }, 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); } }); this.socket.on("user_buy_prop_response",(message)=>{ alert(message.errmsg); }) }, unlock_package_number(){ api.addEventListener({ name: 'unlock_package_number' }, (ret, err)=>{ if( ret ){ // 用户购买道具 this.socket.emit("unlock_package"); } }); this.socket.on("unlock_package_response",(message)=>{ if(parseInt(message.errno) === 1000){ api.sendEvent({ name: 'unlock_package_success', extra: { } }); }else{ api.alert({ title: '提示', msg: message.errmsg, }); } }) }, show_pet(){ // 显示宠物 this.socket.emit("pet_show"); this.socket.on("pet_show_response",(message)=>{ if(parseInt(message.errno) === 1000){ // 把宠物信息保存到本地 this.game.save({"pet_list":message.pet_list}) this.game.save({"pet_number":message.pet_number}) setTimeout(()=>{ api.sendEvent({ name: 'pet_show_success', extra: {} }); },500); }else{ api.alert({ title: '提示', msg: message.errmsg, }); } }) } } }); } </script> </body> </html>
<!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 orchard-frame" id="app"> <div class="background"> <img class="grassland2" src="../static/images/grassland2.png" alt=""> <img class="mushroom1" src="../static/images/mushroom1.png" alt=""> <img class="stake1" src="../static/images/stake1.png" alt=""> <img class="stake2" src="../static/images/stake2.png" alt=""> </div> <div class="pet-box"> <div class="pet"> <img v-if="pet_list.length > 0" class="pet-item" :src="settings.static_url+pet_list[0].image" alt=""> </div> <div class="pet" v-if="pet_number > 1"> <img v-if="pet_list.length>1" class="pet-item" :src="settings.static_url+pet_list[1].image" alt=""> </div> <div class="pet turned_off" v-if="pet_number==1"> <img class="turned_image" src="../static/images/turned_off.png" alt=""> <p>请购买宠物</p> </div> </div> <div class="tree-list"> <div class="tree-box"> <div class="tree"> <img src="../static/images/tree4.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree3.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree4.png" alt=""> </div> </div> <div class="tree-box"> <div class="tree"> <img src="../static/images/tree3.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree2.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree2.png" alt=""> </div> </div> <div class="tree-box"> <div class="tree"> <img src="../static/images/tree1.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree0.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree0.png" alt=""> </div> </div> </div> <div class="prop-list"> <div class="prop"> <img src="../static/images/prop1.png" alt=""> <span>1</span> <p>化肥</p> </div> <div class="prop"> <img src="../static/images/prop2.png" alt=""> <span>0</span> <p>修剪</p> </div> <div class="prop"> <img src="../static/images/prop3.png" alt=""> <span>1</span> <p>浇水</p> </div> <div class="prop"> <img src="../static/images/prop4.png" alt=""> <span>1</span> <p>宠物粮</p> </div> </div> <div class="pet-hp-list"> <div class="pet-hp" v-for="pet in pet_list"> <p>宠物1 饱食度</p> <div class="hp"> <div :style="{width: pet.hp+'%'}" class="process">{{pet.hp}}%</div> </div> </div> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { namespace: '/mofang', token:"", socket: null, pet_list:[], pet_number:[], timeout: 0, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"orchard.html",params:{}}, } }, created(){ this.show_pet_list(); }, methods:{ show_pet_list(){ api.addEventListener({ name: 'pet_show_success' }, (ret, err)=>{ if( ret ){ // 用户购买道具 this.pet_list = this.game.get("pet_list"); this.pet_number = parseInt(this.game.get("pet_number")); this.game.print(this.pet_list); } }); } } }); } </script> </body> </html>
from application.utils.models import BaseModel,db class Goods(BaseModel): """商品基本信息""" __tablename__ = "mf_goods" # 增加道具类型选项 PROP_TYPE = ( (0, "果树"), (1, "宠物"), (2, "植物生长道具"), (3, "宠物粮"), ) remark = db.Column(db.String(255), comment="商品描述") price = db.Column(db.Numeric(7,2), comment="商品价格[余额]") prop_type = db.Column(db.Integer, default=0, comment="道具类型") credit = db.Column(db.Integer, comment="商品价格[果子]") image = db.Column(db.String(255), comment="商品图片")
<!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" v-for="prop in user_package" @click="use_prop(prop.pid)"> <img :src="settings.static_url+prop.image" alt=""> <span>{{prop.num}}</span> </div> <div class="item" v-for="number in unlock_td_number"></div> <div class="item lock" @click="unlock_package()" v-for="number in lock_td_number"></div> </div> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { td: 36, // 背包格子总数量 user_id: "", // 当前登陆用户Id orchard_settings:{}, // 种植园相关公共参数 user_settings:{}, // 用户相关私有参数 user_package:[], // 用户背包信息 prev:{name:"",url:"",params:{}}, current:{name:"package",url:"package.html",params:{}}, } }, computed:{// 计算属性 lock_td_number(){ // 未解锁的格子 return parseInt(this.orchard_settings.package_number_max-this.user_settings.package_number); }, unlock_td_number(){ // 解锁的格子 return parseInt( this.user_settings.package_number - this.user_package.length); } }, created(){ this.user_id = this.game.get("id") || this.game.fget("id"); this.orchard_settings = JSON.parse(this.game.fget("orchard_settings")); this.user_settings = JSON.parse(this.game.fget("user_settings")); this.user_package = JSON.parse(this.game.fget("user_package")); }, methods:{ use_prop(pid){ // 发起使用道具的通知 api.confirm({ title: '提示', msg: '确认使用当前道具吗?', buttons: ['确定', '取消'] }, function(ret, err){ if( ret.buttonIndex == 1 ){ api.sendEvent({ name: 'use_prop', extra: { pid: pid, } }); } }); api.addEventListener({ name: 'pet_use_success' }, (ret, err)=>{ if( ret ){ // 扣除指定道具 var pid = ret.value.pid; for(var i in this.user_package){ if(this.user_package[i].pid == pid){ this.user_package[i].num-=1; if(this.user_package[i].num == 0){ this.user_package.splice(i,1); } } } this.game.fsave({"user_package":this.user_package}); }else{ alert( JSON.stringify( err ) ); } }); }, unlock_package(){ // 解锁格子上限 api.confirm({ title: '提示', msg: '解锁背包上限', buttons: ['确定', '取消'] }, (ret, err)=>{ if( ret.buttonIndex == 1 ){ api.sendEvent({ name: 'unlock_package_number', extra: {} }); api.addEventListener({ name: 'unlock_package_success' }, (ret, err)=>{ this.user_settings.package_number=parseInt(this.user_settings.package_number)+1; this.game.fsave({"user_settings":this.user_settings}); }); } }); }, close_frame(){ this.game.outFrame("package"); }, } }); } </script> </body> </html>
<!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 orchard-frame" id="app"> <div class="background"> <img class="grassland2" src="../static/images/grassland2.png" alt=""> <img class="mushroom1" src="../static/images/mushroom1.png" alt=""> <img class="stake1" src="../static/images/stake1.png" alt=""> <img class="stake2" src="../static/images/stake2.png" alt=""> </div> <div class="pet-box"> <div class="pet"> <img v-if="pet_list.length > 0" class="pet-item" :src="settings.static_url+pet_list[0].image" alt=""> </div> <div class="pet" v-if="pet_number > 1"> <img v-if="pet_list.length>1" class="pet-item" :src="settings.static_url+pet_list[1].image" alt=""> </div> <div class="pet turned_off" v-if="pet_number==1"> <img class="turned_image" src="../static/images/turned_off.png" alt=""> <p>请购买宠物</p> </div> </div> <div class="tree-list"> <div class="tree-box"> <div class="tree"> <img src="../static/images/tree4.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree3.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree4.png" alt=""> </div> </div> <div class="tree-box"> <div class="tree"> <img src="../static/images/tree3.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree2.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree2.png" alt=""> </div> </div> <div class="tree-box"> <div class="tree"> <img src="../static/images/tree1.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree0.png" alt=""> </div> <div class="tree"> <img src="../static/images/tree0.png" alt=""> </div> </div> </div> <div class="prop-list"> <div class="prop"> <img src="../static/images/prop1.png" alt=""> <span>1</span> <p>化肥</p> </div> <div class="prop"> <img src="../static/images/prop2.png" alt=""> <span>0</span> <p>修剪</p> </div> <div class="prop"> <img src="../static/images/prop3.png" alt=""> <span>1</span> <p>浇水</p> </div> <div class="prop"> <img src="../static/images/prop4.png" alt=""> <span>1</span> <p>宠物粮</p> </div> </div> <div class="pet-hp-list"> <div class="pet-hp" v-for="pet in pet_list"> <p>宠物1 饱食度</p> <div class="hp"> <div :style="{width: pet.hp+'%'}" class="process">{{pet.hp}}%</div> </div> </div> </div> </div> <script> apiready = function(){ init(); new Vue({ el:"#app", data(){ return { namespace: '/mofang', token:"", socket: null, pet_list:[], pet_number:[], timeout: 0, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"orchard.html",params:{}}, } }, created(){ this.show_pet_list(); }, methods:{ show_pet_list(){ api.addEventListener({ name: 'pet_show_success' }, (ret, err)=>{ if( ret ){ // 用户购买道具 this.pet_list = this.game.get("pet_list"); this.pet_number = parseInt(this.game.get("pet_number")); } }); } } }); } </script> </body> </html>
<!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:"", settings_info:{ orchard: {}, // 种植园公共参数 user:{}, // 用户私有相关参数 }, socket: null, recharge_list: ['10','20','50','100','200','500','1000'], timeout: 0, prev:{name:"",url:"",params:{}}, current:{name:"orchard",url:"orchard.html",params:{}}, } }, beforeCreate(){ this.game.goFrame("orchard","my_orchard.html", this.current,{ x: 0, y: 180, w: 'auto', h: 410, },null); }, created(){ 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(); this.login(); this.user_package(); this.buy_prop(); this.unlock_package_number(); this.show_pet(); this.use_prop(); }); }, 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}); this.socket.emit("user_prop"); }); }, login(){ this.socket.on("login_response",(message)=>{ this.settings_info.orchard = message.orchard_settings; this.settings_info.user=message.user_settings; this.game.fsave({ "orchard_settings":message.orchard_settings, "user_settings":message.user_settings }); }); }, user_package(){ // 用户背包道具列表 this.socket.on("user_prop_response",(message)=>{ this.game.fsave({ "user_package":message.data, }) }) }, 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); } }); this.socket.on("user_buy_prop_response",(message)=>{ alert(message.errmsg); }) }, use_prop(){ // 使用道具 var pid = 0; api.addEventListener({ name: 'use_prop' }, (ret, err)=>{ if( ret ){ // 用户使用道具 pid = ret.value.pid; this.socket.emit("use_prop",ret.value.pid); } }); this.socket.on("pet_use_response",(message)=>{ if(parseInt(message.errno) === 1000){ api.sendEvent({ name: 'pet_use_success', extra: { pid: pid } }); }else{ api.alert({ title: '提示', msg: message.errmsg, }); } }); }, unlock_package_number(){ api.addEventListener({ name: 'unlock_package_number' }, (ret, err)=>{ if( ret ){ // 用户购买道具 this.socket.emit("unlock_package"); } }); this.socket.on("unlock_package_response",(message)=>{ if(parseInt(message.errno) === 1000){ api.sendEvent({ name: 'unlock_package_success', extra: { } }); }else{ api.alert({ title: '提示', msg: message.errmsg, }); } }) }, show_pet(){ // 显示宠物 this.socket.emit("pet_show"); this.socket.on("pet_show_response",(message)=>{ if(parseInt(message.errno) === 1000){ // 把宠物信息保存到本地 this.game.save({"pet_list":message.pet_list}) this.game.save({"pet_number":message.pet_number}) setTimeout(()=>{ api.sendEvent({ name: 'pet_show_success', extra: {} }); },500); }else{ api.alert({ title: '提示', msg: message.errmsg, }); } }) } } }); } </script> </body> </html>
from datetime import datetime @socketio.on("use_prop", namespace="/mofang") def use_prop(pid): """使用宠物""" room = request.sid user_info = mongo.db.user_info_list.find_one({"sid":request.sid}) user = User.query.get(user_info.get("_id")) if user is None:a socketio.emit("pet_use_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room) return # 1.获取宠物列表 pet_list = user_info.get("pet_list", []) if len(pet_list) > 1: socketio.emit("pet_use_response", {"errno":status.CODE_NO_EMPTY,"errmsg":errmsg.pet_not_empty}, namespace="/mofang", room=room) return # 2. 是否有空余的宠物栏位 pet_number = user_info.get("pet_number",1) if pet_number <= len(pet_list): socketio.emit("pet_use_response", {"errno":status.CODE_NO_EMPTY,"errmsg":errmsg.pet_not_empty}, namespace="/mofang", room=room) return # 3. 初始化当前宠物信息 pet = Goods.query.get(pid) if pet is None: socketio.emit("pet_use_response", {"errno":status.CODE_NO_SUCH_PET,"errmsg":errmsg.not_such_pet}, namespace="/mofang", room=room) return # 4.获取有效期和防御值 exp_data = Setting.query.filter(Setting.name=="pet_expire_%s" % pid).first() ski_data = Setting.query.filter(Setting.name=="pet_skill_%s" % pid).first() if exp_data is None: # 默认7天有效期 expire = 7 else: expire = exp_data.value if ski_data is None: skill = 10 else: skill = ski_data.value # 5.在redis中设置当前宠物的饱食度 pipe = redis.pipeline() pipe.multi() pipe.setex("pet_%s_%s_hp" % (user.id, len(pet_list)+1), 24*60*60, "_") pipe.setex("pet_%s_%s_expire" % (user.id, len(pet_list)+1), int(expire)*24*60*60, "_") pipe.execute() # 6.基本信息保存到mongo mongo.db.user_info_list.update_one({"sid":request.sid},{"$push":{"pet_list":{ "pid": pid, "image": pet.image, "created_time": int( datetime.now().timestamp() ), "skill": skill, }}}) """ db.user_info_list.updateOne({"_id":"52"},{"$push":{"pet_list":{ "pid": 2, "image": "pet1.png", "created_time": 1609727155, "skill": 30, }}}) """ # 7.扣除背包中的道具数量 prop_list = user_info.get("prop_list",{}) for key,value in prop_list.items(): if key == ("prop_%s" % pid): if int(value) > 1: prop_list[key] = int(value) - 1 else: prop_list.pop(key) break mongo.db.user_info_list.update_one({"sid":room},{"$set":{"prop_list":prop_list}}) user_prop() pet_show() socketio.emit("pet_use_response", {"errno": status.CODE_OK, "errmsg": errmsg.ok}, namespace="/mofang", room=room)