种植园

一、商城页面

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><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"><p class="title"><img src="../static/images/money.png" alt="">钱包</p><p class="num">99,999.00</p></div><div class="balance"><p class="title"><img src="../static/images/integral.png" alt="">果子</p><p class="num">99,999.00</p></div></div><div class="menu-list"><div class="menu"><img src="../static/images/menu1.png" alt="">排行榜</div><div class="menu"><img src="../static/images/menu2.png" alt="">签到有礼</div><div class="menu" @click='go_orchard_shop'><img src="../static/images/menu3.png" alt="">道具商城</div><div class="menu"><img src="../static/images/menu4.png" alt="">邮件中心</div></div></div><div class="footer"><ul class="menu-list"><li class="menu">新手</li><li class="menu">背包</li><li class="menu-center" @click='go_orchard_shop'>商店</li><li class="menu">消息</li><li class="menu">好友</li></ul></div></div><script>apiready = function(){init();new Vue({el:"#app",data(){return {music_play:true,namespace: '/mofang',token:"",socket: null,timeout: 0,prev:{name:"",url:"",params:{}},current:{name:"orchard",url:"orchard.html",params:{}},}},created(){this.game.goFrame('orchard', 'my_orchard.html', this.current, {x: 0,y: 180,w: 'auto',h: 'auto',}, null);this.checkout();},methods:{checkout(){var token = this.game.get("access_token") || this.game.fget("access_token");this.game.checkout(this,token,(new_access_token)=>{this.connect();});},connect(){// socket连接this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']});this.socket.on('connect', ()=>{this.game.print("开始连接服务端");});},go_index(){this.game.outWin("orchard");},go_friends(){this.game.goFrame('friends', 'friends.html', this.current);this.game.goFrame('friend_list', 'friend_list.html', this.current, {x: 0,y: 190,w: 'auto',h: 'auto',}, null, true);},go_home(){this.game.goWin('user', 'user.html', this.current);},go_orchard_shop(){// 种植园商店this.game.goFrame('orchard_shop', 'shop.html', this.current, null, {type: 'push',subType: 'from_top',duration: 300});}}});}</script>
</body>
</html>

新建shop.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 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"><div class="avatar shop_item"><img src="../static/images/fruit_tree.png" alt=""></div><div class="info"><p class="username">果树</p><p class="time">200</p></div><div class="status">200</div></div></div></div></div><script>apiready = function(){init();new Vue({el:"#app",data(){return {user_id: "", // 当前登陆用户Idprev:{name:"",url:"",params:{}},current:{name:"orchard",url:"shop.html",params:{}},}},created(){this.user_id = this.game.get("id") || this.game.fget("id");},methods:{close_frame(){this.game.outFrame("orchard_shop");},}});}</script>
</body>
</html>

main.css,代码:

.shop .shop_list{margin-left: 1rem;margin-top: -5rem;
}

二、服务端提供商品api

商店的商品:1. 种子果树标题价格描述图片使用流程相关状态: 种子期, 成长期, 成熟期, 树桩种子期: 3  x 60 x 60成长期: 6  x 60 x 60成熟期: 12 x 60 x 60树桩 :  -12. 宠物小狗1,小狗2,小狗3,小狗4标题价格描述图片使用流程相关:饱食度: <20%(饥饿) <50%(正常) <100%(饱腹)生命期: -1(永久)保护命中率  : 10%   0-1   <10%3. 狗粮狗粮1,狗粮2,狗粮3标题价格描述图片使用流程相关:饱食度: 20%有效期: 4. 道具化肥,....标题价格描述图片使用流程相关:缩短时间: 1小时

apps/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="商品价格")image = db.Column(db.String(255), comment="商品图片")

apps/users/models.py,模型代码:

from werkzeug.security import generate_password_hash, check_password_hash
from application.utils.models import BaseModel,db
class User(BaseModel):"""用户基本信息"""__tablename__ = "mf_user"name = db.Column(db.String(255), index=True, comment="用户账户")_password = db.Column(db.String(255), comment="登录密码")_transaction_password = db.Column(db.String(255), comment='交易密码')nickname = db.Column(db.String(255), comment="用户昵称")age = db.Column(db.SmallInteger, comment="年龄")money = db.Column(db.Numeric(7,2), comment="账户余额")credit = db.Column(db.Numeric(7, 2), default=0, comment="果子积分")ip_address = db.Column(db.String(255), default="", index=True, comment="登录IP")intro = db.Column(db.String(500), default="", comment="个性签名")avatar = db.Column(db.String(255), default="", comment="头像url地址")sex = db.Column(db.SmallInteger, default=0, comment="性别")  # 0表示未设置,保密, 1表示男,2表示女email = db.Column(db.String(32), index=True, default="", nullable=False, comment="邮箱地址")mobile = db.Column(db.String(32), index=True, nullable=False, comment="手机号码")unique_id = db.Column(db.String(255), index=True, default="", comment="客户端唯一标记符")province = db.Column(db.String(255), default="", comment="省份")city = db.Column(db.String(255), default="", comment="城市")area = db.Column(db.String(255), default="", comment="地区")info = db.relationship('UserProfile', backref='user', uselist=False)@propertydef password(self):return self._password@password.setterdef password(self, rawpwd):"""密码加密"""self._password = generate_password_hash(rawpwd)def check_password(self, rawpwd):"""验证密码"""return check_password_hash(self.password, rawpwd)@propertydef transaction_password(self):return self._transaction_password@transaction_password.setterdef transaction_password(self, rawpwd):"""密码加密"""self._transaction_password = generate_password_hash(rawpwd)def check_transaction_password(self, rawpwd):"""验证密码"""return check_password_hash(self.transaction_password, rawpwd)class UserProfile(BaseModel):"""用户详情信息表"""__tablename__ = "mf_user_profile"user_id = db.Column(db.Integer,db.ForeignKey('mf_user.id'), comment="用户ID")education = db.Column(db.Integer, comment="学历教育")middle_school = db.Column(db.String(255), default="", comment="初中/中专")high_school = db.Column(db.String(255), default="", comment="高中/高职")college_school = db.Column(db.String(255), default="", comment="大学/大专")profession_cate = db.Column(db.String(255), default="", comment="职业类型")profession_info = db.Column(db.String(255), default="", comment="职业名称")position = db.Column(db.SmallInteger, default=0, comment="职位/职称")emotion_status = db.Column(db.SmallInteger, default=0, comment="情感状态")birthday =db.Column(db.DateTime, default="", comment="生日")hometown_province = db.Column(db.String(255), default="", comment="家乡省份")hometown_city = db.Column(db.String(255), default="", comment="家乡城市")hometown_area = db.Column(db.String(255), default="", comment="家乡地区")hometown_address = db.Column(db.String(255), default="", comment="家乡地址")living_province = db.Column(db.String(255), default="", comment="现居住省份")living_city = db.Column(db.String(255), default="", comment="现居住城市")living_area = db.Column(db.String(255), default="", comment="现居住地区")living_address = db.Column(db.String(255), default="", comment="现居住地址")def __repr__(self):return "<%s %s>" % (self.__class__.__name__, self.user.name)class UserRelation(BaseModel):"""用户关系"""__tablename__ = 'mf_user_relation'relation_status_chioce = ((1, '好友'),(2, '关注'),)relation_type_chioce = ((1, '手机'),(2, '账号'),(3, '邮箱'),(4, '昵称'),(5, '群聊'),(6, '二维码邀请注册'),)send_user = db.Column(db.Integer, comment='用户1')  # 主动构建关系的用户receive_user = db.Column(db.Integer, comment='用户2')  # 接受关系请求的用户relation_type = db.Column(db.Integer, default=1, comment='构建关系类型')relation_status = db.Column(db.Integer, default=1, comment='关系状态')def __repr__(self):return '用户%s通过%s对%s进行了%s操作' % (self.send_user, self.relation_type, self.receive_user, self.status)

数据迁移,代码:

python manage.py db migrate -m "add goods table"
python manage.py db upgrade

在admin站点中进行模型管理注册,apps/orchard/admin.py,代码:


# 根据模型自动生成页面
from .models import Goods
from flask_admin.contrib.sqla import ModelView
from application import admin, dbclass GoodsAdminModel(ModelView):# 列表页显示字段列表column_list = ['id', 'name', 'price']# 列表页可以直接编辑的字段列表column_editable_list = ['price']# 是否允许查看详情can_view_details = True# 列表页显示直接可以搜索数据的字典column_searchable_list = ['name', 'price']# 过滤器column_filters = ['name']# 单页显示数据量page_size = 10admin.add_view(GoodsAdminModel(Goods, db.session, name="商品", category="种植园"))

在数据库添加SQL数据,代码:

INSERT INTO mofang.mf_goods
(id, name, is_deleted, orders, status, created_time, updated_time, remark, price, image)
VALUES
(1, '果树', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '果树', 10.00, null),
(2, '小狗1号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '小狗1号', 100.00, null),
(3, '小狗2号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '小狗2号', 200.00, null),
(4, '小狗3号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '小狗3号', 300.00, null),
(5, '小狗4号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '小狗4号', 100.00, null),
(6, '狗粮1号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '狗粮1号', 10.00, null),
(7, '狗粮2号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '狗粮2号', 5.00, null),
(8, '化肥1号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '化肥1号', 3.00, null),
(9, '化肥2号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '化肥2号', 6.00, null),
(10, '化肥3号', 0, 0, 1, '2020-12-28 16:09:39', '2020-12-28 16:09:39', '化肥3号', 9.00, null);

解决App打包编译以后的跨域限制

解决app打包生成以后,页面无法请求服务端数据的跨域问题。
无法获取数据的原因是,当前APP中获取数据是通过ajax来发送请求的,因为我们当前的APP是混合APP,所以实际来说,这种混合APP就是一个浏览器内核构建的。因此也会存在同源策略的访问限制,因此我们需要在服务端实现跨域资源共享。

服务端终端运行:

pip install -U flask-cors

application/__init__.py,代码:

import os, sysfrom flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
from flask_session import Session
from flask_migrate import Migrate, MigrateCommand
from flask_jsonrpc import JSONRPC
from flask_marshmallow import Marshmallow
from flask_jwt_extended import JWTManager
from flask_admin import Admin
from flask_babelex import Babel
from faker import Faker
from flask_pymongo import PyMongo
from flask_qrcode import QRcode
from flask_socketio import SocketIO
from flask_cors import CORSfrom application.utils import init_blueprint
from application.utils.config import load_config
from application.utils.session import init_session
from application.utils.logger import Log
from application.utils.commands import load_command# 创建终端脚本管理对象
manager = Manager()# 创建数据库链接对象
db = SQLAlchemy()# redis链接对象
redis = FlaskRedis()# Session存储对象
session_store = Session()# 数据迁移实例对象
migrate = Migrate()# 日志对象
log = Log()# jsonrpc模块实例对象
jsonrpc = JSONRPC()# 数据转换器的对象创建
ma = Marshmallow()# jwt认证模块实例化
jwt = JWTManager()# flask_admin模块实例化
admin = Admin()# flask_babelex模块实例化
babel = Babel()# mongoDB
mongo = PyMongo()# qrcode
QRCode = QRcode()# socketio
socketio = SocketIO()# flask_cors
cors = CORS()def init_app(config_path):"""全局初始化"""# 创建app应用对象app = Flask(__name__)# 项目根目录app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 加载导包路径sys.path.insert(0, os.path.join(app.BASE_DIR, "application/utils/language"))# 加载配置Config = load_config(config_path)app.config.from_object(Config)# 数据库初始化db.init_app(app)app.db = dbredis.init_app(app)mongo.init_app(app)# 数据转换器的初始化ma.init_app(app)# session存储初始化init_session(app)session_store.init_app(app)# 数据迁移初始化migrate.init_app(app, db)# 添加数据迁移的命令到终端脚本工具中manager.add_command('db', MigrateCommand)# 日志初始化app.log = log.init_app(app)# 蓝图注册init_blueprint(app)# jsonrpc初始化jsonrpc.service_url = "/api"  # api接口的url地址前缀jsonrpc.init_app(app)# jwt初始化jwt.init_app(app)# admin初始化admin.init_app(app)# 国际化本地化模块的初始化babel.init_app(app)# 初始化终端脚本工具manager.app = app# 数据种子生成器[faker]app.faker = Faker(app.config.get('LANGUAGE'))# qrcode初始化配置QRCode.init_app(app)# corscors.init_app(app, resources={r"/api/*": {'origins': "*"}})# socketiosocketio.init_app(app, cors_allowed_origins=app.config['CORS_ALLOWED_ORIGINS'], async_mode=app.config['ASYNC_MODE'],debug=app.config['DEBUG'])# 改写runserver命令if sys.argv[1] == 'runserver':manager.add_command('run', socketio.run(app, host=app.config['HOST'], port=app.config['PORT']))# 注册自定义命令load_command(manager)return manager

提供商品列表给客户端,apps/orchard/views.py, 代码:


from application import jsonrpc
from status import APIStatus as status
from message import ErrorMessage as message
from  application import redis
from .models import Goods
from application.apps.users.models import User
from flask_jwt_extended import jwt_required, get_jwt_identity
from .marshmallow import GoodsInfoSchema
@jsonrpc.method(name='Orchard.goods.list')
@jwt_required  # 验证jwt
def goods_list(page=1, limit=10):"""商品列表"""current_user_id = get_jwt_identity()user = User.query.get(current_user_id)if user is None:return {'errno': status.CODE_NO_USER,'errmsg': message.user_not_exists,}pagination = Goods.query.filter(Goods.is_deleted == False,Goods.status == True).paginate(page, per_page=limit)# 转换数据格式gis = GoodsInfoSchema()goods_list = gis.dump(pagination.items, many=True)return {'errno': status.CODE_OK,'errmsg': message.ok,'goods_list': goods_list,'pages': pagination.pages}

marshmallow,代码:


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()class Meta:model = Goodsfields = ['id', 'name', 'price', 'image', 'remark']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

三、客户端获取商品列表并进行展示

客户端就可以在打开商品的时候, 获取商品列表,shop.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 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" 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: "", // 当前登陆用户Idgoods_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,}},{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);});})},}});}</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><script src="../static/js/socket.io.js"></script>
</head>
<body><div class="app orchard" id="app"><img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png"><div class="orchard-bg"><img src="../static/images/bg2.png"><img class="board_bg2" src="../static/images/board_bg2.png"></div><img class="back" @click="go_index" src="../static/images/user_back.png" alt=""><div class="header"><div class="info" @click='go_home'><div class="avatar"><img class="avatar_bf" src="../static/images/avatar_bf.png" alt=""><img class="user_avatar" src="../static/images/avatar.png" alt=""><img class="avatar_border" src="../static/images/avatar_border.png" alt=""></div><p class="user_name">好听的昵称</p></div><div class="wallet"><div class="balance" @click='user_recharge'><p class="title"><img src="../static/images/money.png" alt="">钱包</p><p class="num">99,999.00</p></div><div class="balance"><p class="title"><img src="../static/images/integral.png" alt="">果子</p><p class="num">99,999.00</p></div></div><div class="menu-list"><div class="menu"><img src="../static/images/menu1.png" alt="">排行榜</div><div class="menu"><img src="../static/images/menu2.png" alt="">签到有礼</div><div class="menu" @click='go_orchard_shop'><img src="../static/images/menu3.png" alt="">道具商城</div><div class="menu"><img src="../static/images/menu4.png" alt="">邮件中心</div></div></div><div class="footer"><ul class="menu-list"><li class="menu">新手</li><li class="menu">背包</li><li class="menu-center" @click='go_orchard_shop'>商店</li><li class="menu">消息</li><li class="menu">好友</li></ul></div></div><script>apiready = function(){init();new Vue({el:"#app",data(){return {music_play:true,namespace: '/mofang',token:"",socket: null,recharge_list: ['10','20','50','100','200','500','1000']timeout: 0,prev:{name:"",url:"",params:{}},current:{name:"orchard",url:"orchard.html",params:{}},}},created(){this.game.goFrame('orchard', 'my_orchard.html', this.current, {x: 0,y: 180,w: 'auto',h: 'auto',}, null);this.checkout();},methods:{user_recharge(){// 充值api.actionSheet({title: '余额充值',cancelTitle: '取消',buttons: this.recharge_list}, function(ret, err){if( ret ){// 充值金额money = this.recharge_list[ret.buttonIndex-1];// 调用支付宝充值}else{}});},checkout(){var token = this.game.get("access_token") || this.game.fget("access_token");this.game.checkout(this,token,(new_access_token)=>{this.connect();});},connect(){// socket连接this.socket = io.connect(this.settings.socket_server + this.namespace, {transports: ['websocket']});this.socket.on('connect', ()=>{this.game.print("开始连接服务端");});},go_index(){this.game.outWin("orchard");},go_friends(){this.game.goFrame('friends', 'friends.html', this.current);this.game.goFrame('friend_list', 'friend_list.html', this.current, {x: 0,y: 190,w: 'auto',h: 'auto',}, null, true);},go_home(){this.game.goWin('user', 'user.html', this.current);},go_orchard_shop(){// 种植园商店this.game.goFrame('orchard_shop', 'shop.html', this.current, null, {type: 'push',subType: 'from_top',duration: 300});}}});}</script>
</body>
</html>

settings.js代码:

function init(){if (Game) {var game = new Game("../mp3/bg1.mp3");Vue.prototype.game = game;}server_url = 'http://192.168.20.180:5000';if(axios){// 初始化axiosaxios.defaults.baseURL = server_url+"/api" // 服务端api接口网关地址axios.defaults.timeout = 2500; // 请求超时时间axios.defaults.withCredentials = false; // 跨域请求资源的情况下,忽略cookie的发送Vue.prototype.axios = axios;Vue.prototype.uuid  = UUID.generate;}// 接口相关的配置项Vue.prototype.settings = {captcha_app_id: "2041284967",  // 腾讯防水墙验证码应用IDavatar_url: server_url+"/users/avatar",static_url: server_url+"/static/",code_url: server_url,socket_server: 'ws://192.168.20.180:5000',socket_namespace: '/mofang',}
}

接下来,在APICloud中上传提交代码到云端进行云编译。
1.首先来到APIcloud开发者web后台,把Alipayplus模块加载到APP。

2.点击Alipayplus进入模块详情。

3.把模块使用到指定APP中。

集成Alipayplus模块完成支付


接下来,服务端中需要完成的就是生成订单参数和接收支付结果,所以我们先 安装alipay的sdk,集成到flask项目中。
终端运行:

pip install python-alipay-sdk --upgrade

配置支付宝的公钥和私钥,保存到application/apps/users/keys目录下。

cd application/apps/users/
mkdir keys
cd keys
openssl
OpenSSL> genrsa -out app_private_key.pem 2048  # 私钥
OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem # 导出公钥
OpenSSL> exit

保存商户公钥到支付宝开放平台, 并从开放平台中把支付宝公钥保存到项目中。

users/models.py,代码:

...
class Recharge(BaseModel):__tablename__ = "mf_user_recharge"status  = db.Column(db.Boolean, default=True, comment="状态(是否支付)")out_trade_number  = db.Column(db.String(64), unique=True, comment="订单号")user_id = db.Column(db.Integer, comment="用户")money = db.Column(db.Numeric(7,2), comment="充值金额")trade_number = db.Column(db.String(64), unique=True, comment="流水号")

数据迁移,命令:

python manage.py db migrate -m "add recharge table"
python manage.py db upgrade

魔坊APP项目-17-种植园,商城页面、服务端提供商品api,解决App打包编译以后的跨域限制、客户端获取商品列表并进行展示,集成Alipayplus模块完成支付相关推荐

  1. 魔坊APP项目-18-种植园,基于支付宝提供的沙箱测试环境开发支付接口、服务端, 处理支付结果的同步通知和异步通知、修复页面底部菜单无法被点击的BUG

    种植园 一.基于支付宝提供的沙箱测试环境开发支付接口 沙箱环境: https://openhome.alipay.com/platform/appDaily.htm?tab=info 开发文档: ht ...

  2. 魔坊APP项目-22-种植园,种植栏的功能实现,客户端根据激活状态和未激活状态分别显示树桩、服务端提供种植植物的相关数据、解锁树桩、植物相关道具使用

    种植园 一.种植栏的功能实现 1. 客户端需要的植物相关参数: 总树桩数量, 当前用户激活树桩数量, 当前种植的树桩数量, 树桩列表状态 2. 客户端根据激活状态和未激活状态分别显示树桩 3. 服务端 ...

  3. 魔坊APP项目-21-种植园,宠物栏的功能实现、服务端提供显示宠物的api接口、客户端中展示宠物栏和宠物列表以及饱食度、宠物道具的使用

    种植园 一.宠物栏的功能实现 1. 宠物的显示 2. 宠物的使用 3. 宠物的饱食度 4. 宠物的开锁 1.服务端提供显示宠物的api接口 socket.py,代码 ... import math f ...

  4. 魔坊APP项目-15-邀请好友(业务逻辑流程图、服务端提供邀请好友的二维码生成接口、客户端通过第三方识别微信二维码,服务端提供接口允许访问、App配置私有协议,允许第三方应用通过私有协议,唤醒APP)

    邀请好友 1.业务逻辑流程图 客户端提供点击"邀请好友"以后的页面frame,html/invite.html,代码: <!DOCTYPE html> <html ...

  5. 魔方APP项目-06-用户注册,完成短信验证码的校验、基于Celery实现短信异步发送、用户登录,jwt登陆认证、服务端提供用户登录的API接口

    一.用户注册- 1.完成短信验证码的校验 application.utils.language.message,代码: class ErrorMessage():ok = "ok" ...

  6. 服务端渲染与 Universal React App

    随着 Webpack 等前端构建工具的普及,客户端渲染因为其构建方便,部署简单等方面的优势,逐渐成为了现代网站的主流渲染模式.而在刚刚发布的 React v16.0 中,改进后更为优秀的服务端渲染性能 ...

  7. Diy页面服务端渲染解决方案

    Diy页面服务端渲染解决方案 参考文章: (1)Diy页面服务端渲染解决方案 (2)https://www.cnblogs.com/Wenwang/p/5138826.html 备忘一下.

  8. SharePoint 2013 APP 开发示例 (六)服务端跨域访问 Web Service (REST API)

    上个示例(SharePoint 2013 APP 开发示例 (五)跨域访问 Web Service (REST API))是基于JavaScript,运行在web browser内去访问REST AP ...

  9. app测试、h5测试、服务端测试区别

    (存放位置)1.h5页面放在服务端,网速慢的时候,页面出来的就慢,app的页面都是本地写出来的.可以用弱网测试看出一些区别来.(访问机制)2.h5的页面都是访问url,app都是本地写出来的页面,不需 ...

最新文章

  1. linux通过rinetd工具进行端口映射/转发/重定向
  2. 汇编: 更灵活的定位内存地址的方法
  3. python3 join函数_Python中.join()和os.path.join()两个函数的用法详解
  4. 字符动图_手把手教你做一个python+matplotlib的炫酷的数据可视化动图
  5. underscore.js 页面数据渲染
  6. Excel 一键上传到数据库
  7. C++ Primer 5th 第1章 开始
  8. Android UI系列-----ScrollView和HorizontalScrollView
  9. php公众获取用户信息,PHP--通过公众号获取用户微信信息
  10. PyTorch学习—13.优化器optimizer的概念及常用优化器
  11. linux看视频播放器官方下载,SMPlayer - Linux 电影播放器
  12. 《物联篮球计分器》Android应用程序开发-期末课程设计
  13. 【搞定Go语言】第3天22:常用的HTTP服务压测工具介绍
  14. 联想台式计算机重装系统教程,台式机装系统步骤 联想台式电脑怎么重装系统...
  15. 京东静态网页设计案例(1)
  16. 前端网页版ps,你用过了吗?
  17. Android高级特性笔记
  18. 乐乐音乐播放器 欢迎页面(二)
  19. 快搜新爬虫研发的曲折之路,十年磨一剑
  20. SpringCloud_Eureka:java.lang.NoClassDefFoundError: org/springframework/boot/actuate/health/HealthAgg

热门文章

  1. 全国计算机等级考试在线报名入口,2021年3月全国计算机等级考试NCRE报名入口ncre-bm.neea.cn...
  2. Vue经典实例之table表格奇偶行不同颜色、鼠标移入变色、点击变色,一看就明白
  3. ❤️一起谈一谈js中的宏任务和微任务!
  4. 好莱坞十大导演排名及其代表作,你看过多少?
  5. https链接网页图片无法显示问题解决办法
  6. excel中如何使内容不要超出单元格
  7. 关于jxl的一点知识
  8. 解决springboot使用多线程无法注入Bean问题,不能注入Service或者Mapper
  9. 如何在 PHP 8.1 中使用枚举
  10. 新作文杂志新作文杂志社新作文编辑部2022年第8期目录