day116:MoFang:顯示背包解鎖/未解鎖格子數&顯示背包的道具物品&背包解鎖
- 2021 年 1 月 11 日
- 筆記
- PythonS31-筆記, Python全棧31期-筆記
格子的初始化數量, 每次解鎖背包格子的價格等等.
參數資訊的保存與之前項目配置的資訊有所不同, 不同的地方在於, 參數資訊僅僅是種植園額業務參數,會在項目運營的時候允許有所改動,而項目配置的變數參數則在項目上線以後基本不做改動.
class Setting(BaseModel): """參數資訊""" __tablename__ = "mf_orchard_setting" title=db.Column(db.String(255), comment="提示文本") value=db.Column(db.String(255), comment="數值")
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (1, 'package_number_base', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '背包格子基礎數量', '4'), (2, 'package_number_max', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '背包格子上限數量', '32'), (3, 'td_prop_max', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '單個格子存儲道具數量上限', '10'), (4, 'package_unlock_price_1', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '解鎖背包格子價格5-8', '10'), (5, 'package_unlock_price_2', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '解鎖背包格子價格9-12', '50'), (6, 'package_unlock_price_3', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '解鎖背包格子價格13-16', '100'), (7, 'package_unlock_price_4', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '解鎖背包格子價格17-20', '200'), (8, 'package_unlock_price_5', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '解鎖背包格子價格21-24', '500'), (9, 'package_unlock_price_6', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '解鎖背包格子價格25-28', '1000'), (10, 'package_unlock_price_7', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '解鎖背包格子價格29-32', '5000');
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,Setting 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, }) # A.返回種植園的相關配置參數 orchard_settings = {} # 1.查詢公共配置表得到種植園所有公共配置 setting_list = Setting.query.filter(Setting.is_deleted==False, Setting.status==True).all() # 2.重新構造數據結構類型{配置名1:配置對應的值1,配置名2:配置對應的值2} for item in setting_list: orchard_settings[item.name] = item.value # B.返回當前用戶相關的配置參數 user_settings = {} # 1.從mongo中查找用戶資訊 dict = mongo.db.user_info_list.find_one({"sid":request.sid}) # 2.新用戶如果在mongo查詢不到格子數,則用戶的默認格子數為4 if dict.get("package_number") is None: user_settings["package_number"] = orchard_settings.get("package_number_base",4) # 3.將用戶格子數更新到mongo中 mongo.db.user_info_list.update_one({"sid":request.sid},{"$set":{"package_number": user_settings["package_number"]}}) # 4.如果在mongo中能查詢到當前用戶的格子數,則將格子數取出來賦值給user_setting else: user_settings["package_number"] = dict.get("package_number") # 5.將種植園公共配置和用戶私有配置返回給前端 socketio.emit("login_response", { "errno":status.CODE_OK, "errmsg":errmsg.ok, "orchard_settings":orchard_settings, "user_settings":user_settings }, namespace="/mofang", room=room)

<!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:{}}, } }, 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(); this.login(); }); }, 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}); }); }, // ***用戶登錄種植園後獲取種植園公有配置和私有配置*** 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 }); }); }, 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>
用戶登錄種植園後獲取種植園公有配置和私有配置
2.通過computed計算屬性計算出用戶解鎖格子數和用戶未解鎖格子數
3.在HTML頁面通過for循環顯示解鎖格子和未解鎖格子

<!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="number in unlock_td_number"></div> <div class="item lock" 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:{}, // 用戶相關私有參數 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); } }, 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")); }, methods:{ close_frame(){ this.game.outFrame("package"); }, } }); } </script> </body> </html>
背包顯示真實的解鎖格子和未解鎖格子
INSERT INTO mofang.mf_orchard_setting (id, name, is_deleted, orders, status, created_time, updated_time, title, value) VALUES (3, 'td_prop_max', 0, 1, 1, '2020-12-30 17:40:46', '2020-12-30 17:40:44', '單個格子存儲道具數量上限', '10'),
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,Setting from status import APIStatus as status from message import ErrorMessage as errmsg @socketio.on("user_prop", namespace="/mofang") def user_prop(): """用戶道具""" # 1.查詢當前用戶的mongo對象 userinfo = mongo.db.user_info_list.find_one({"sid":request.sid}) # 2.獲取當前用戶的道具物品列表 prop_list = userinfo.get("prop_list") prop_id_list = [] # 用戶所擁有所有道具的id值 for prop_str,num in prop_list.items(): pid = int(prop_str[5:]) # 獲取每個道具的id值 prop_id_list.append(pid) # prop_id_list用來存儲用戶所擁有所有道具的id值 data = [] # 3.查詢用戶所擁有的所有道具的所有資訊(道具價格、道具圖片等資訊) prop_list_data = Goods.query.filter(Goods.id.in_(prop_id_list)).all() # 4.查詢種植園公共配置:每個格子可容納的最大數量 setting = Setting.query.filter(Setting.name == "td_prop_max").first() if setting is None: td_prop_max = 10 else: td_prop_max = int(setting.value) # 5.循環用戶擁有的每個道具 for prop_data in prop_list_data: # 查詢用戶所擁有每個道具對應的數量 num = int( prop_list[("prop_%s" % prop_data.id)]) if td_prop_max > num: # 如果道具數量小於單個格子最大容納值 data.append({ # 構造data數據結構:包括道具id/道具數量/道具圖片 "num": num, "image": prop_data.image, "pid": prop_data.id }) else: # 如果道具數量大於單個格子最大容納值 padding_time = num // td_prop_max # 545//100=5 padding_last = num % td_prop_max # 545%100=45 # 容量已滿的整格子 arr = [{ "num": td_prop_max, "image": prop_data.image, "pid": prop_data.id }] * padding_time # 餘下的未滿的單獨再佔一個格子 if padding_last != 0: arr.append({ "num": padding_last, "image": prop_data.image, "pid": prop_data.id }) data = data + arr room = request.sid # 6.將背包中的道具物品/道具數量/所佔格子等返回給前端 socketio.emit("user_prop_response", { "errno": status.CODE_OK, "errmsg": errmsg.ok, "data":data, }, namespace="/mofang", room=room)
1.用戶登錄種植園後,前端向後端發送請求(user_prop),請求去獲取用戶背包的道具數據
connect(){ this.socket.emit("user_prop"); }); },
2.後端接收請求(user_prop),將用戶道具數據響應(user_prop_response)給前端
@socketio.on("user_prop", namespace="/mofang") def user_prop(): socketio.emit("user_prop_response", { "errno": status.CODE_OK, "errmsg": errmsg.ok, "data":data, }, namespace="/mofang", room=room)
3.前端接收來自後端的響應數據(user_prop_response),並將用戶道具數據存儲在前端
user_package(){ // 用戶背包道具列表 this.socket.on("user_prop_response",(message)=>{ this.game.fsave({ "user_package":message.data, }) }) },

<!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:{}}, } }, 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(); this.login(); this.user_package(); }); }, 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); } }); }, } }); } </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> </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" 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){ // 發起使用道具的通知 }, close_frame(){ this.game.outFrame("package"); }, } }); } </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,Setting 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, }) # 返回種植園的相關配置參數 orchard_settings = {} setting_list = Setting.query.filter(Setting.is_deleted==False, Setting.status==True).all() """ 現在的格式: [<Setting package_number_base>, <Setting package_number_max>, <Setting package_unlock_price_1>] 需要返回的格式: { package_number_base:4, package_number_max: 32, ... } """ for item in setting_list: orchard_settings[item.name] = item.value # 返回當前用戶相關的配置參數 user_settings = {} # 從mongo中查找用戶資訊,判斷用戶是否激活了背包格子 dict = mongo.db.user_info_list.find_one({"sid":request.sid}) # 背包格子 if dict.get("package_number") is None: user_settings["package_number"] = orchard_settings.get("package_number_base",4) mongo.db.user_info_list.update_one({"sid":request.sid},{"$set":{"package_number": user_settings["package_number"]}}) else: user_settings["package_number"] = dict.get("package_number") socketio.emit("login_response", { "errno":status.CODE_OK, "errmsg":errmsg.ok, "orchard_settings":orchard_settings, "user_settings":user_settings }, namespace="/mofang", room=room) @socketio.on("user_buy_prop", namespace="/mofang") def user_buy_prop(data): """用戶購買道具""" room = request.sid # 從mongo中獲取當前用戶資訊 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("user_buy_prop_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room) return # 從mysql中獲取商品價格 prop = Goods.query.get(data["pid"]) 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: """此前沒有購買任何道具""" 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}}) get_user_prop() socketio.emit("user_buy_prop_response", {"errno":status.CODE_OK,"errmsg":errmsg.ok}, namespace="/mofang", room=room) @socketio.on("user_prop", namespace="/mofang") def user_prop(): get_user_prop() def get_user_prop(): """用戶道具""" userinfo = mongo.db.user_info_list.find_one({"sid":request.sid}) prop_list = userinfo.get("prop_list") prop_id_list = [] for prop_str,num in prop_list.items(): pid = int(prop_str[5:]) prop_id_list.append(pid) data = [] prop_list_data = Goods.query.filter(Goods.id.in_(prop_id_list)).all() setting = Setting.query.filter(Setting.name == "td_prop_max").first() if setting is None: td_prop_max = 10 else: td_prop_max = int(setting.value) for prop_data in prop_list_data: num = int( prop_list[("prop_%s" % prop_data.id)]) if td_prop_max > num: data.append({ "num": num, "image": prop_data.image, "pid": prop_data.id }) else: padding_time = num // td_prop_max padding_last = num % td_prop_max arr = [{ "num": td_prop_max, "image": prop_data.image, "pid": prop_data.id }] * padding_time if padding_last != 0: arr.append({ "num": padding_last, "image": prop_data.image, "pid": prop_data.id }) data = data + arr room = request.sid socketio.emit("user_prop_response", { "errno": status.CODE_OK, "errmsg": errmsg.ok, "data":data, }, namespace="/mofang", room=room)

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,Setting from status import APIStatus as status from message import ErrorMessage as errmsg @socketio.on("user_buy_prop", namespace="/mofang") def user_buy_prop(data): """用戶購買道具""" 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("user_buy_prop_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room) return # 判斷背包物品存儲是否達到上限 use_package_number = int(user_info.get("use_package_number",0)) # 當前已經使用的格子數量 package_number = int(user_info.get("package_number",0)) # 當前用戶已經解鎖的格子數量 setting = Setting.query.filter(Setting.name == "td_prop_max").first() if setting is None: td_prop_max = 10 else: td_prop_max = int(setting.value) # ***計算購買道具以後需要額外佔用的格子數量*** if ("prop_%s" % data["pid"]) in user_info.get("prop_list"): # 如果用戶購買過當前道具 """A.曾經購買過當前道具""" # 1.獲取購買前的道具數量 prop_num = int( user_info.get("prop_list")["prop_%s" % data["pid"]]) # 2.如果成功購買道具以後的數量 new_prop_num = prop_num+int(data["num"]) # 3.計算購買前道具所佔用的格子數量 old_td_num = prop_num // td_prop_max if prop_num % td_prop_max > 0: old_td_num+=1 # 4.計算如果成功購買後道具所佔用的格子數量 new_td_num = new_prop_num // td_prop_max if new_prop_num % td_prop_max > 0: new_td_num+=1 # 5.計算本次購買道具所需要佔用的格子數量 td_num = new_td_num - old_td_num else: """B.新增購買的道具""" # 計算本次購買道具需要佔用的格子數量 if int(data["num"]) > td_prop_max: """需要多個格子""" td_num = int(data["num"]) // td_prop_max if int(data["num"]) % td_prop_max > 0: td_num+=1 else: """需要一個格子""" td_num = 1 if use_package_number+td_num > package_number: """如果超出存儲上限,提示錯誤:達到背包上限""" socketio.emit("user_buy_prop_response", {"errno": status.CODE_NO_PACKAGE, "errmsg": errmsg.no_package}, namespace="/mofang", room=room) return # 從mysql中獲取商品價格 prop = Goods.query.get(data["pid"]) 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: """此前沒有購買任何道具""" 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) # 返回最新的用戶道具列表 user_prop() @socketio.on("user_prop", namespace="/mofang") def user_prop(): """用戶道具""" userinfo = mongo.db.user_info_list.find_one({"sid":request.sid}) prop_list = userinfo.get("prop_list") prop_id_list = [] for prop_str,num in prop_list.items(): pid = int(prop_str[5:]) prop_id_list.append(pid) data = [] prop_list_data = Goods.query.filter(Goods.id.in_(prop_id_list)).all() setting = Setting.query.filter(Setting.name == "td_prop_max").first() if setting is None: td_prop_max = 10 else: td_prop_max = int(setting.value) for prop_data in prop_list_data: num = int( prop_list[("prop_%s" % prop_data.id)]) if td_prop_max > num: data.append({ "num": num, "image": prop_data.image, "pid": prop_data.id }) else: padding_time = num // td_prop_max padding_last = num % td_prop_max arr = [{ "num": td_prop_max, "image": prop_data.image, "pid": prop_data.id }] * padding_time if padding_last != 0: arr.append({ "num": padding_last, "image": prop_data.image, "pid": prop_data.id }) data = data + arr # 保存當前用戶已經使用的格子數量 mongo.db.user_info_list.update_one({"sid":request.sid},{"$set":{"use_package_number":len(data)}}) room = request.sid socketio.emit("user_prop_response", { "errno": status.CODE_OK, "errmsg": errmsg.ok, "data":data, }, namespace="/mofang", room=room)
用戶購買道具的時候,判斷背包存儲是否達到上限
from message import ErrorMessage as Message from .models import Goods,db from marshmallow_sqlalchemy import SQLAlchemyAutoSchema,auto_field from marshmallow import post_dump class GoodsInfoSchema(SQLAlchemyAutoSchema): id = auto_field() name = auto_field() price = auto_field() image = auto_field() remark = auto_field() credit = auto_field() class Meta: model = Goods fields = ["id","name","price","image","remark","credit"] sql_session = db.session @post_dump() def mobile_format(self, data, **kwargs): data["price"] = "%.2f" % data["price"] if data["image"] == None: data["image"] = "" return data

<!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"> <span v-if="goods.price>0">{{goods.price}}</span> <span v-else>{{goods.credit}}個果子</span> </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>
在商城頁面根據金額/積分顯示不同商品
在購買商品成功以後, 計算金額和積分的扣除, socket.py程式碼:

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,Setting,db from status import APIStatus as status from message import ErrorMessage as errmsg # 建立socket通訊 # @socketio.on("connect", namespace="/mofang") # def user_connect(): # """用戶連接""" # print("用戶%s連接過來了!" % request.sid) # # 主動響應數據給客戶端 # socketio.emit("server_response","hello",namespace="/mofang") # 斷開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, }) # 返回種植園的相關配置參數 orchard_settings = {} setting_list = Setting.query.filter(Setting.is_deleted==False, Setting.status==True).all() """ 現在的格式: [<Setting package_number_base>, <Setting package_number_max>, <Setting package_unlock_price_1>] 需要返回的格式: { package_number_base:4, package_number_max: 32, ... } """ for item in setting_list: orchard_settings[item.name] = item.value # 返回當前用戶相關的配置參數 user_settings = {} # 從mongo中查找用戶資訊,判斷用戶是否激活了背包格子 dict = mongo.db.user_info_list.find_one({"sid":request.sid}) # 背包格子 if dict.get("package_number") is None: user_settings["package_number"] = orchard_settings.get("package_number_base",4) mongo.db.user_info_list.update_one({"sid":request.sid},{"$set":{"package_number": user_settings["package_number"]}}) else: user_settings["package_number"] = dict.get("package_number") socketio.emit("login_response", { "errno":status.CODE_OK, "errmsg":errmsg.ok, "orchard_settings":orchard_settings, "user_settings":user_settings }, namespace="/mofang", room=room) @socketio.on("user_buy_prop", namespace="/mofang") def user_buy_prop(data): """用戶購買道具""" room = request.sid # 從mongo中獲取當前用戶資訊 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("user_buy_prop_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room) return # 判斷背包物品存儲是否達到上限 use_package_number = int(user_info.get("use_package_number",0)) # 當前詩經使用的格子數量 package_number = int(user_info.get("package_number",0)) # 當前用戶已經解鎖的格子數量 # 本次購買道具需要使用的格子數量 setting = Setting.query.filter(Setting.name == "td_prop_max").first() if setting is None: td_prop_max = 10 else: td_prop_max = int(setting.value) # 計算購買道具以後需要額外佔用的格子數量 if ("prop_%s" % data["pid"]) in user_info.get("prop_list",{}): """曾經購買過當前道具""" prop_num = int( user_info.get("prop_list")["prop_%s" % data["pid"]]) # 購買前的道具數量 new_prop_num = prop_num+int(data["num"]) # 如果成功購買道具以後的數量 old_td_num = prop_num // td_prop_max if prop_num % td_prop_max > 0: old_td_num+=1 new_td_num = new_prop_num // td_prop_max if new_prop_num % td_prop_max > 0: new_td_num+=1 td_num = new_td_num - old_td_num else: """新增購買的道具""" # 計算本次購買道具需要佔用的格子數量 if int(data["num"]) > td_prop_max: """需要多個格子""" td_num = int(data["num"]) // td_prop_max if int(data["num"]) % td_prop_max > 0: td_num+=1 else: """需要一個格子""" td_num = 1 if use_package_number+td_num > package_number: """超出存儲上限""" socketio.emit("user_buy_prop_response", {"errno": status.CODE_NO_PACKAGE, "errmsg": errmsg.no_package}, namespace="/mofang", room=room) return # 從mysql中獲取商品價格 prop = Goods.query.get(data["pid"]) if user.money > 0: # 當前商品需要通過RMB購買 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 else: """當前通過果子進行購買""" if int(user.credit) < int(prop.credit) * int(data["num"]): socketio.emit("user_buy_prop_response", {"errno": status.CODE_NO_CREDIT, "errmsg": errmsg.credit_no_enough}, namespace="/mofang", room=room) return # 從mongo中獲取用戶列表資訊,提取購買的商品數量進行累加和餘額 query = {"sid": request.sid} if user_info.get("prop_list") is None: """此前沒有購買任何道具""" 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}}) # 扣除餘額或果子 if prop.price > 0: user.money = float(user.money) - float(prop.price) * int(data["num"]) else: user.credit = int(user.credit) - int(prop.credit) * int(data["num"]) db.session.commit() # 返回購買成功的資訊 socketio.emit("user_buy_prop_response", {"errno":status.CODE_OK,"errmsg":errmsg.ok}, namespace="/mofang", room=room) # 返回最新的用戶道具列表 user_prop() @socketio.on("user_prop", namespace="/mofang") def user_prop(): """用戶道具""" userinfo = mongo.db.user_info_list.find_one({"sid":request.sid}) prop_list = userinfo.get("prop_list",{}) prop_id_list = [] for prop_str,num in prop_list.items(): pid = int(prop_str[5:]) prop_id_list.append(pid) data = [] prop_list_data = Goods.query.filter(Goods.id.in_(prop_id_list)).all() setting = Setting.query.filter(Setting.name == "td_prop_max").first() if setting is None: td_prop_max = 10 else: td_prop_max = int(setting.value) for prop_data in prop_list_data: num = int( prop_list[("prop_%s" % prop_data.id)]) if td_prop_max > num: data.append({ "num": num, "image": prop_data.image, "pid": prop_data.id }) else: padding_time = num // td_prop_max padding_last = num % td_prop_max arr = [{ "num": td_prop_max, "image": prop_data.image, "pid": prop_data.id }] * padding_time if padding_last != 0: arr.append({ "num": padding_last, "image": prop_data.image, "pid": prop_data.id }) data = data + arr mongo.db.user_info_list.update_one({"sid":request.sid},{"$set":{"use_package_number":len(data)}}) room = request.sid socketio.emit("user_prop_response", { "errno": status.CODE_OK, "errmsg": errmsg.ok, "data":data, }, namespace="/mofang", room=room)
購買商品成功後,計算金額和積分的扣除
@socketio.on("unlock_package", namespace="/mofang") def unlock_package(): """解鎖背包""" # 從mongo獲取當前用戶解鎖的格子數量 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("unlock_package_response", {"errno":status.CODE_NO_USER,"errmsg":errmsg.user_not_exists}, namespace="/mofang", room=room) return package_number = int(user_info.get("package_number")) num = 7 - (32 - package_number) // 4 # 沒有解鎖的格子 # 從資料庫中獲取解鎖背包的價格 setting = Setting.query.filter(Setting.name == "package_unlock_price_%s" % num).first() if setting is None: unlock_price = 0 else: unlock_price = int(setting.value) # 判斷是否有足夠的積分或者價格 room = request.sid if user.money < unlock_price: socketio.emit("unlock_package_response", {"errno": status.CODE_NO_MONEY, "errmsg": errmsg.money_no_enough}, namespace="/mofang", room=room) return # 解鎖成功 user.money = float(user.money) - float(unlock_price) db.session.commit() # mongo中調整數量 mongo.db.user_info_list.update_one({"sid":request.sid},{"$set":{"package_number": package_number+1}}) # 返回解鎖的結果 socketio.emit("unlock_package_response", { "errno": status.CODE_OK, "errmsg": errmsg.ok}, namespace="/mofang", room=room)

<!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:{}}, } }, 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(); this.login(); this.user_package(); this.buy_prop(); this.unlock_package_number(); }); }, 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, }); } }) } } }); } </script> </body> </html>
背包解鎖:orchard.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> </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){ // 發起使用道具的通知 }, 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+=1; }); } }); }, close_frame(){ this.game.outFrame("package"); }, } }); } </script> </body> </html>
背包解鎖:package.html


