flask 与 小程序 下单提交-LMLPHP

mina/pages/order/index.wxml

<view class="container">
     <view class="address-box">
        <view class="add-address" hidden="{{default_address}}">
            <view class="title" bindtap="addressSet">新增收货地址</view>
        </view>
        <view class="show-address" hidden="{{!default_address}}" bindtap="selectAddress">
            <view class="name-tel">{{default_address.name}}  {{default_address.mobile}}</view>
            <view class="addr-text">{{default_address.detail}}</view>
        </view>
     </view>
     <view class="goods-list">
        <view class="list-title">商品列表</view>
        <view class="a-goods" wx:for-items="{{goods_list}}" wx:key="{{index}}">
            <view class="img-box">
                <image src="{{item.pic_url}}" class="img" />
            </view>
            <view class="text-box">
                <view class="arow arow01">
                    <view class="goods-name">{{item.name}}</view>
                    <view class="goods-price">¥ {{item.price}}</view>
                </view>
                <view class="arow">
                    <view class="goods-label"></view>
                    <view class="goods-num">x {{item.number}}</view>
                </view>
            </view>
        </view>
     </view>
     <view class="peisong-way">
        <view class="row-box">
            <view class="row-label">配送方式</view>
            <view class="right-text" wx:if="{{yun_price > 0}}">快递</view>
            <view class="right-text" wx:if="{{yun_price == 0}}">包邮</view>
        </view>
        <view class="row-box">
            <view class="row-label">备注</view>
            <view class="right-text">
                <input name="remark" type="text" class="liuyan" placeholder="如需备注请输入" />
            </view>
        </view>
     </view>

     <view class="goods-info">
        <view class="row-box">
            <view class="row-label">商品金额</view>
            <view class="right-text">¥ {{pay_price}}</view>
        </view>
        <view class="row-box">
            <view class="row-label">运费</view>
            <view class="right-text">+ ¥ {{yun_price}}</view>
        </view>
     </view>

     <view class="jiesuan-box">
        <view class="left-price">
            <view class="total">合计:¥ {{total_price}}</view>
        </view>
        <button class="to-pay-btn" bindtap="createOrder">提交订单</button>
    </view>
</view>

mina/pages/order/index.js

//获取应用实例
var app = getApp();

Page({
    data: {
        goods_list: [],
        default_address: null,
        yun_price: "0.00",
        pay_price: "0.00",
        total_price: "0.00",
        params: null,
        express_address_id:0
    },
    onLoad: function (e) {
        var that = this;
        that.setData({
            params: JSON.parse(e.data)
        });
    },
    onShow: function () {
        var that = this;
         this.getOrderInfo();
    },
    createOrder: function (e) {
        wx.showLoading();
        var that = this;
        var data = {
            type: this.data.params.type,
            goods: JSON.stringify(this.data.params.goods),
            express_address_id: that.data.default_address.id
        };
        wx.request({
            url: app.buildUrl("/order/create"),
            header: app.getRequestHeader(),
            method: 'POST',
            data: data,
            success: function (res) {
                wx.hideLoading();
                var resp = res.data;
                if (resp.code != 200) {
                    app.alert({"content": resp.msg});
                    return;
                }
                wx.navigateTo({
                    url: "/pages/my/order_list"
                });
            }
        });

    },
    addressSet: function () {
        wx.navigateTo({
            url: "/pages/my/addressSet?id=0"
        });
    },
    selectAddress: function () {
        wx.navigateTo({
            url: "/pages/my/addressList"
        });
    },
    getOrderInfo: function () {
        var that = this;
        var data = {
            type: this.data.params.type,
            goods: JSON.stringify(this.data.params.goods)
        };
        wx.request({
            url: app.buildUrl("/order/info"),
            header: app.getRequestHeader(),
            method: 'POST',
            data: data,
            success: function (res) {
                var resp = res.data;
                if (resp.code != 200) {
                    app.alert({"content": resp.msg});
                    return;
                }

                that.setData({
                    goods_list: resp.data.food_list,
                    default_address: resp.data.default_address,
                    yun_price: resp.data.yun_price,
                    pay_price: resp.data.pay_price,
                    total_price: resp.data.total_price,
                });

                if( that.data.default_address ){
                    that.setData({
                         express_address_id: that.data.default_address.id
                    });
                }
            }
        });
    }

});

onLoad:function(e){}

params: JSON.parse(e.data)

JSON.parse()是JavaScript中的一个方法,用于将一个JSON字符串解析为对应的JavaScript对象。它接受一个JSON字符串作为参数,并返回一个JavaScript对象。

在你提供的引用中,JSON.parse()的用法如下:

var str = '{"name":"huangxiaojian","age":"23"}';
var obj = JSON.parse(str);
console.log(obj); // 输出:{ name: "huangxiaojian", age: "23" }

JSON.stringify()是JavaScript中的另一个方法,用于将一个JavaScript对象转换为对应的JSON字符串。它接受一个JavaScript对象作为参数,并返回一个JSON字符串。

在你提供的引用中,JSON.stringify()的用法如下:

var obj = { a: 1, b: 2 };
var str = JSON.stringify(obj);
console.log(str); // 输出:{"a":1,"b":2}

params: JSON.parse(e.data)的意思是将变量e.data中的JSON字符串解析为JavaScript对象。

createOrder:function(e){  }

wx.showLoading():

wx.showLoading(Object object) | 微信开放文档

显示 loading 提示框。需主动调用 wx.hideLoading 才能关闭提示框

wx.hideLoading():

web/controllers/api/Order.py

# -*- coding: utf-8 -*-
from web.controllers.api import route_api
from flask import request, jsonify,g
from application import app, db
import json, decimal
from common.models.food.Food import Food
from common.models.pay.PayOrder import PayOrder
from common.libs.UrlManager import UrlManager
from common.libs.Helper import getCurrentDate
from common.libs.pay.PayService import PayService
from common.libs.pay.WeChatService import WeChatService
from common.libs.member.CartService import CartService
from common.models.member.MemberAddress import MemberAddress
from common.models.member.OauthMemberBind import OauthMemberBind


@route_api.route("/order/info", methods=[ "POST" ])
def orderInfo():
	resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
	req = request.values
	params_goods = req['goods'] if 'goods' in req else None
	member_info = g.member_info
	params_goods_list = []
	if params_goods:
		params_goods_list = json.loads(params_goods)

	food_dic = {}
	for item in params_goods_list:
		food_dic[item['id']] = item['number']

	food_ids = food_dic.keys()
	food_list = Food.query.filter(Food.id.in_(food_ids)).all()
	data_food_list = []
	yun_price = pay_price = decimal.Decimal(0.00)
	if food_list:
		for item in food_list:
			tmp_data = {
				"id": item.id,
				"name": item.name,
				"price": str(item.price),
				'pic_url': UrlManager.buildImageUrl(item.main_image),
				'number': food_dic[item.id]
			}
			pay_price = pay_price + item.price * int( food_dic[item.id] )
			data_food_list.append(tmp_data)

	# 获取地址
	address_info = MemberAddress.query.filter_by( is_default = 1,member_id = member_info.id,status = 1 ).first()
	default_address = ''
	if address_info:
		default_address = {
			"id": address_info.id,
			"name": address_info.nickname,
			"mobile": address_info.mobile,
			"address":"%s%s%s%s"%( address_info.province_str,address_info.city_str,address_info.area_str,address_info.address )
		}

	resp['data']['food_list'] = data_food_list
	resp['data']['pay_price'] = str(pay_price)
	resp['data']['yun_price'] = str(yun_price)
	resp['data']['total_price'] = str(pay_price + yun_price)
	resp['data']['default_address'] = default_address
	return jsonify(resp)

@route_api.route("/order/create", methods=[ "POST"])
def orderCreate():
	resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
	req = request.values
	type = req['type'] if 'type' in req else ''
	note = req['note'] if 'note' in req else ''
	express_address_id = int( req['express_address_id'] ) if 'express_address_id' in req and req['express_address_id'] else 0
	params_goods = req['goods'] if 'goods' in req else None

	items = []
	if params_goods:
		items = json.loads(params_goods)

	if len( items ) < 1:
		resp['code'] = -1
		resp['msg'] = "下单失败:没有选择商品~~"
		return jsonify(resp)

	address_info = MemberAddress.query.filter_by( id = express_address_id ).first()
	if not address_info or not address_info.status:
		resp['code'] = -1
		resp['msg'] = "下单失败:快递地址不对~~"
		return jsonify(resp)

	member_info = g.member_info
	target = PayService()
	params = {
		"note":note,
		'express_address_id':address_info.id,
		'express_info':{
			'mobile':address_info.mobile,
			'nickname':address_info.nickname,
			"address":"%s%s%s%s"%( address_info.province_str,address_info.city_str,address_info.area_str,address_info.address )
		}
	}
	resp = target.createOrder( member_info.id ,items ,params)
	#如果是来源购物车的,下单成功将下单的商品去掉
	if resp['code'] == 200 and type == "cart":
		CartService.deleteItem( member_info.id,items )

	return jsonify( resp )

@route_api.route("/order/pay", methods=[ "POST"])
def orderPay():
	resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
	member_info = g.member_info
	req = request.values
	order_sn = req['order_sn'] if 'order_sn' in req else ''
	pay_order_info = PayOrder.query.filter_by( order_sn = order_sn,member_id = member_info.id ).first()
	if not pay_order_info:
		resp['code'] = -1
		resp['msg'] = "系统繁忙。请稍后再试~~"
		return jsonify(resp)

	oauth_bind_info = OauthMemberBind.query.filter_by( member_id =  member_info.id ).first()
	if not oauth_bind_info:
		resp['code'] = -1
		resp['msg'] = "系统繁忙。请稍后再试~~"
		return jsonify(resp)

	config_mina = app.config['MINA_APP']
	notify_url = app.config['APP']['domain'] + config_mina['callback_url']

	target_wechat = WeChatService( merchant_key=config_mina['paykey'] )

	data = {
		'appid': config_mina['appid'],
		'mch_id': config_mina['mch_id'],
		'nonce_str': target_wechat.get_nonce_str(),
		'body': '订餐',  # 商品描述
		'out_trade_no': pay_order_info.order_sn,  # 商户订单号
		'total_fee': int( pay_order_info.total_price * 100 ),
		'notify_url': notify_url,
		'trade_type': "JSAPI",
		'openid': oauth_bind_info.openid
	}

	pay_info = target_wechat.get_pay_info( pay_data=data)

	#保存prepay_id为了后面发模板消息
	pay_order_info.prepay_id = pay_info['prepay_id']
	db.session.add( pay_order_info )
	db.session.commit()

	resp['data']['pay_info'] = pay_info
	return jsonify(resp)

@route_api.route("/order/callback", methods=[ "POST"])
def orderCallback():
	result_data = {
		'return_code': 'SUCCESS',
		'return_msg': 'OK'
	}
	header = {'Content-Type': 'application/xml'}
	config_mina = app.config['MINA_APP']
	target_wechat = WeChatService(merchant_key=config_mina['paykey'])
	callback_data = target_wechat.xml_to_dict( request.data )
	app.logger.info( callback_data  )
	sign = callback_data['sign']
	callback_data.pop( 'sign' )
	gene_sign = target_wechat.create_sign( callback_data )
	app.logger.info(gene_sign)
	if sign != gene_sign:
		result_data['return_code'] = result_data['return_msg'] = 'FAIL'
		return target_wechat.dict_to_xml(result_data), header
	if callback_data['result_code'] != 'SUCCESS':
		result_data['return_code'] = result_data['return_msg'] = 'FAIL'
		return target_wechat.dict_to_xml(result_data), header

	order_sn = callback_data['out_trade_no']
	pay_order_info = PayOrder.query.filter_by(order_sn=order_sn).first()
	if not pay_order_info:
		result_data['return_code'] = result_data['return_msg'] = 'FAIL'
		return target_wechat.dict_to_xml(result_data), header

	if int( pay_order_info.total_price * 100  ) != int( callback_data['total_fee'] ):
		result_data['return_code'] = result_data['return_msg'] = 'FAIL'
		return target_wechat.dict_to_xml(result_data), header

	if pay_order_info.status == 1:
		return target_wechat.dict_to_xml(result_data), header

	target_pay = PayService()
	target_pay.orderSuccess( pay_order_id = pay_order_info.id,params = { "pay_sn":callback_data['transaction_id'] } )
	target_pay.addPayCallbackData( pay_order_id = pay_order_info.id, data = request.data)
	return target_wechat.dict_to_xml(result_data), header

@route_api.route("/order/ops", methods=[ "POST"])
def orderOps():
	resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
	req = request.values
	member_info = g.member_info
	order_sn = req['order_sn'] if 'order_sn' in req else ''
	act = req['act'] if 'act' in req else ''
	pay_order_info = PayOrder.query.filter_by(order_sn=order_sn, member_id=member_info.id).first()
	if not pay_order_info:
		resp['code'] = -1
		resp['msg'] = "系统繁忙。请稍后再试~~"
		return jsonify(resp)


	if act == "cancel":
		target_pay = PayService( )
		ret = target_pay.closeOrder( pay_order_id=pay_order_info.id )
		if not ret:
			resp['code'] = -1
			resp['msg'] = "系统繁忙。请稍后再试~~"
			return jsonify(resp)
	elif act == "confirm":
		pay_order_info.express_status = 1
		pay_order_info.updated_time = getCurrentDate()
		db.session.add( pay_order_info )
		db.session.commit()

	return jsonify(resp)




@route_api.route("/order/create", methods=[ "POST"])

flask 与 小程序 下单提交-LMLPHP

type: cart
goods: [{"id":23, "price":"36.00", "number":1}, {"id":18, "price":"36.00", "number":1}]

json.loads()

是Python标准库json模块中的一个方法,用于将JSON字符串转换为Python数据类型。它的使用方法如下所示:

import json

json_str = '{"name": "John", "age": 30, "city": "New York"}'
data = json.loads(json_str)

print(data)  # 输出:{'name': 'John', 'age': 30, 'city': 'New York'}

在上面的例子中,我们首先导入了json模块。然后,我们定义了一个JSON字符串json_str,其中包含了一个名为"name"的键和对应的值"John",一个名为"age"的键和对应的值30,以及一个名为"city"的键和对应的值"New York"。接下来,我们使用json.loads()方法将JSON字符串转换为Python数据类型,并将结果赋值给变量data。最后,我们打印出data的值,即转换后的Python字典。

需要注意的是,json.loads()只适用于读取JSON字符串,如果想要从JSON文件中读取数据,请使用json.load()方法

jsonify()

jsonify()是Flask框架中的一个函数,用于将Python对象转换为JSON格式的响应。它会自动设置响应头部的"Content-Type"为"application/json",简化了返回JSON数据的操作。

以下是两种使用jsonify()函数返回JSON数据的例子:

使用字典作为参数:

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/json1', methods=['GET'])
def json_demo1():
    return jsonify({
        "username": 'yoyo',
        "email": "111@qq.com"
    })

if __name__ == '__main__':
    app.run()

使用键值对作为参数:

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/json2', methods=['GET'])
def json_demo2():
    return jsonify(
        username="yoyo",
        email="111@qq.com"
    )

if __name__ == '__main__':
    app.run()

这两个例子中,当访问对应的路由时,会返回一个JSON格式的响应,其中包含了指定的键值对或字典。

Food.query.filter(Food.id.in_(food_ids)).all()中in的作用

Food.query.filter(Food.id.in_(food_ids)).all()中,in_是一个SQLAlchemy的查询操作符,用于判断一个字段的值是否在给定的列表中。它可以用于过滤查询结果,只返回满足条件的记录。

具体来说,Food.id.in_(food_ids)表示筛选出Food表中id字段的值在food_ids列表中的记录。这样,filter()方法就会返回满足这个条件的所有记录。

举个例子,假设food_ids是一个包含[1, 2, 3]的列表,那么Food.query.filter(Food.id.in_(food_ids)).all()将返回Food表中id为1、2、3的所有记录

数据库common/models/member/MemberAddress

DROP TABLE IF EXISTS `member_address`;
CREATE TABLE `member_address` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `member_id` int(11) NOT NULL DEFAULT '0' COMMENT '会员id',
  `nickname` varchar(20) NOT NULL DEFAULT '' COMMENT '收货人姓名',
  `mobile` varchar(11) NOT NULL DEFAULT '' COMMENT '收货人手机号码',
  `province_id` int(11) NOT NULL DEFAULT '0' COMMENT '省id',
  `province_str` varchar(50) NOT NULL DEFAULT '' COMMENT '省名称',
  `city_id` int(11) NOT NULL DEFAULT '0' COMMENT '城市id',
  `city_str` varchar(50) NOT NULL DEFAULT '' COMMENT '市名称',
  `area_id` int(11) NOT NULL DEFAULT '0' COMMENT '区域id',
  `area_str` varchar(50) NOT NULL DEFAULT '' COMMENT '区域名称',
  `address` varchar(100) NOT NULL DEFAULT '' COMMENT '详细地址',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否有效 1:有效 0:无效',
  `is_default` TINYINT(1)  NOT NULL  DEFAULT '0'  COMMENT '默认地址',
  `updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后一次更新时间',
  `created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '插入时间',
  PRIMARY KEY (`id`),
  KEY `idx_member_id_status` (`member_id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员收货地址';
flask-sqlacodegen 'mysql://root:root@127.0.0.1/food_db' --tables member_address --outfile "common/models/member/MemberAddress.py"  --flask

注意: Order.py   Cart.py Member.py 这些文件要导入到__init__.py中

flask 与 小程序 下单提交-LMLPHP

若不导入则在小程序页面中显示  页面不存在

flask 与 小程序 下单提交-LMLPHP

web/controllers/api/__init__.py

# -*- coding: utf-8 -*-
from flask import Blueprint
route_api = Blueprint( 'api_page',__name__ )
from web.controllers.api.Member import *
from web.controllers.api.Food import *
from web.controllers.api.Order import *

from web.controllers.api.Cart import *


@route_api.route("/")
def index():
    return "Mina Api V1.0~~"

flask 与 小程序 下单提交-LMLPHP

01-21 07:45