python 全栈开发,Day128(创建二维码,扫码,创建玩具的基本属性)
昨日内容回顾
1.app播放音乐 plus.audio.createPlayer(文件路径/URL) player.play() 播放音乐 player.pause() 暂停播放 player.resume() 继续播放 player.stop() 停止播放,清空player对象 # 当停止之后,无法在使用play() resume()继续播放 2.app遥控玩具播放内容 Websocket通讯 实现手机遥控app app:{content_id:123,to_user:123456} {music_name:"123.wav",to_user:123456} 服务器端:拿到to_user的websocket 如果使用content_id做查询 music_name:直接返回 玩具端:返回给玩具端{code:0,from_user:654321,data:music_name} 3.玩具控制管理页面
下载代码:
https://github.com/987334176/Intelligent_toy/archive/v1.1.zip
注意:由于涉及到版权问题,此附件没有图片和音乐。请参考链接,手动采集一下!
请参考链接:
https://www.cnblogs.com/xiao987334176/p/9647993.html#autoid-3-4-0
一、创建二维码
为什么要创建二维码呢?主要是做防伪的!
一个玩具,很容易就会被其他厂商复制处理。那么如何区分,一个玩具就是我生产的呢?
出厂时,将设备id写入数据库。同时将设备id生成二维码,贴在玩具背后!那么用户扫码,就可以判断玩具的真伪了!
打开联图的二维码官网:
打开MongoDB,复制一条id,粘贴到官网。它会即时生成!
它还有一个API接口,也可以生成二维码。
比如将123,生成二维码
http://qr.liantu.com/api.php?text=123
浏览器直接访问上面这个地址,效果如下:
接下来,就使用这个API生成二维码!
进入flask后端,修改settings.py,增加二维码API以及保存目录
import pymongo client = pymongo.MongoClient(host="127.0.0.1", port=27017) MONGO_DB = client["bananabase"] RET = { # 0: false 2: True "code": 0, "msg": "", # 提示信息 "data": {} } XMLY_URL = "http://m.ximalaya.com/tracks/" # 喜马拉雅链接 CREATE_QR_URL = "http://qr.liantu.com/api.php?text=" # 生成二维码API # 文件目录 import os AUDIO_FILE = os.path.join(os.path.dirname(__file__), "audio") # 音频 AUDIO_IMG_FILE = os.path.join(os.path.dirname(__file__), "audio_img") # 音频图片 DEVICE_CODE_PATH = os.path.join(os.path.dirname(__file__), "device_code") # 二维码
新建目录device_code
新建一个文件QRcode.py,用来生成二维码图片
from uuid import uuid4 import hashlib, time,os import requests import setting # 生成唯一设备id,f-string是Python 3.6语法 device_id = f"{uuid4()}{time.time()}" device_id_md5 = hashlib.md5(device_id.encode("utf8")) # 生成md5对象 qr_code = device_id_md5.hexdigest() # 获取md5的值 qr_url = f"{setting.CREATE_QR_URL}{qr_code}" # 生成二维码访问链接 res = requests.get(qr_url) # 使用GET请求 # 拼接二维码图片保存路径 code_file = os.path.join(setting.DEVICE_CODE_PATH,f"{qr_code}.jpg") with open(code_file, "wb") as f: f.write(res.content) # 写入文件
此时目录结构如下:
./
├── audio
├── audio_img
├── device_code
├── im_serv.py
├── manager.py
├── QRcode.py
├── serv
│ ├── content.py
│ └── get_file.py
├── setting.py
├── static
│ └── recorder.js
├── templates
│ └── index.html
└── xiaopapa.py
执行QRcode.py,此时device_code目录会生成一个图片
接下来,将这部分代码封装成函数。并写入MongoDB中
修改 QRcode.py
from uuid import uuid4 import hashlib, time,os import requests import setting def create_device_id(count=1): device_list = [] for i in range(count): # 生成唯一设备id,f-string是Python 3.6语法 device_id = f"{uuid4()}{time.time()}" device_id_md5 = hashlib.md5(device_id.encode("utf8")) # 生成md5对象 qr_code = device_id_md5.hexdigest() # 获取md5的值 qr_url = f"{setting.CREATE_QR_URL}{qr_code}" # 生成二维码访问链接 res = requests.get(qr_url) # 使用GET请求 # 拼接二维码图片保存路径 code_file = os.path.join(setting.DEVICE_CODE_PATH,f"{qr_code}.jpg") with open(code_file, "wb") as f: f.write(res.content) # 写入文件 device_list.append({"device_id": qr_code}) # 追加到列表中 time.sleep(0.2) # 睡眠0.2秒,防止被封锁IP setting.MONGO_DB.devices.insert_many(device_list) # 写入多条记录 create_device_id(5) # 生成5条记录
清空device_code目录,并执行QRcode.py。等待10秒左右,就会有5个图片了
二、扫码
barcode
Barcode模块管理条码扫描,支持常见的条码(一维码及二维码)的扫描识别功能。可调用设备的摄像头对条码图片扫描进行数据输入,解码后返回码数据及码类型。通过plus.barcode可获取条码码管理对象。
参考链接:
http://www.html5plus.org/doc/zh_cn/barcode.html
create
创建Barcode对象
Barcode plus.barcode.create(id, filters, styles);
说明:
调用此方法创建后并不会显示,需要调用Webview窗口的append方法将其添加到Webview窗口后才能显示。 注意:此时需要通过styles参数的top/left/width/height属性设置控件的位置及大小。
参数:
- id: ( String ) 必选 Barcode对象的全局标识
可用于通过plus.barcode.getBarcodeById()方法查找已经创建的Barcode对象。 - filters: ( Array[ Number ] ) 可选 要识别的条码类型过滤器,为条码类型常量数组
条码识别引擎可支持多种二维码及一维码类型,默认情况支持QR、EAN13、EAN8三种类型。 可通过此参数设置需要支持的更多条码类型(注意:设置支持的条码类型越多,扫码识别效率将会降低)。 - styles: ( BarcodeStyles ) 可选 Barcode扫码控件的样式
可定义Barcode扫码控件的样式,如扫码框、扫码条的颜色等。
返回值:
Barcode : Barcode扫码控件对象
示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Barcode Example</title> <script type="text/javascript" > var barcode = null; // 扫码成功回调 function onmarked(type, result) { var text = '未知: '; switch(type){ case plus.barcode.QR: text = 'QR: '; break; case plus.barcode.EAN13: text = 'EAN13: '; break; case plus.barcode.EAN8: text = 'EAN8: '; break; } alert( text+result ); } // 创建Barcode扫码控件 function createBarcode() { if(!barcode){ barcode = plus.barcode.create('barcode', [plus.barcode.QR], { top:'100px', left:'0px', width: '100%', height: '200px', position: 'static' }); barcode.onmarked = onmarked; plus.webview.currentWebview().append(barcode); } barcode.start(); } </script> <style type="text/css"> *{ -webkit-user-select: none; } html,body{ margin: 0px; padding: 0px; height: 100%; } </style> </head> <body > <button onclick="createBarcode()">创建扫码控件</button> </body> </html>
Barcode
Barcode扫码控件对象
interface plus.barcode.Barcode { // Methods function void start(options); function void cancel(); function void close(); function void setFlash(open); // Events function void onmarked(); function void onerror(); }
说明:
Barcode对象表示条码识别控件对象,在窗口中显示条码识别控件,使用此对象可自定义条码识别界面。
构造:
- Barcode.constructor(domId, filters, styles): 创建Barcode对象
方法:
事件:
示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Barcode Example</title> <script type="text/javascript" > // 扩展API加载完毕后调用onPlusReady回调函数 document.addEventListener( "plusready", onPlusReady, false ); // 扩展API加载完毕,现在可以正常调用扩展API function onPlusReady() { var e = document.getElementById("scan"); e.removeAttribute( "disabled" ); } var scan = null; function onmarked( type, result ) { var text = '未知: '; switch(type){ case plus.barcode.QR: text = 'QR: '; break; case plus.barcode.EAN13: text = 'EAN13: '; break; case plus.barcode.EAN8: text = 'EAN8: '; break; } alert( text+result ); } function startRecognize() { scan = new plus.barcode.Barcode('bcid'); scan.onmarked = onmarked; } function startScan() { scan.start(); } function cancelScan() { scan.cancel(); } function setFlash() { scan.setFlash(); } </script> <style type="text/css"> *{ -webkit-user-select: none; } html,body{ margin: 0px; padding: 0px; height: 100%; } #bcid { background:#0F0; height:480px; width:360px; } </style> </head> <body > <input type='button' onclick='startRecognize()' value='创建扫码控件' /> <input type='button' onclick='startScan()' value='开始扫码' /> <input type='button' onclick='cancelScan()' value='取消扫码' /> <input type='button' onclick='setFlash()' value='开启闪光灯' /> <div id= "bcid"></div> <input type='text' id='text'/> </body> </html>
参考链接:
http://www.html5plus.org/doc/zh_cn/barcode.html#plus.barcode.create
打开HBuilder项目MyApp,新建一个文件qrcode.html
修改 toy_manager.html,将 扫描二维码.html 改成 qrcode.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">管理我的玩具</h1> </header> <div class="mui-content"> <ul class="mui-table-view" id="toy_list"> <li class="mui-table-view-cell mui-media"> <a id="add_toy"> <img class="mui-media-object mui-pull-left" src="images/add.png"> <div class="mui-media-body"> 你还没有玩具 <p class="mui-ellipsis">点击此处扫描二维码添加玩具</p> </div> </a> </li> </ul> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() document.getElementById("add_toy").addEventListener("tap", function() { mui.openWindow({ url: "qrcode.html", id: "qrcode.html", }) }) </script> </html>
修改 qrcode.html,创建Barcode对象并开启扫码
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">扫描玩具二维码</h1> </header> <div class="mui-content"> <div style="height: 550px;" id="qr"></div> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() mui.plusReady(function() { // 创建Barcode对象 var barcode = new plus.barcode.Barcode('qr'); barcode.start(); // 开始条码识别 }) </script> </html>
连接真机
由于模拟器调用摄像头,这里必须要用真实的手机连接才行!
那么如何连接呢?使用360手机助手!
360手机助手
我的手机是华为P9,其实华为手机助手,也可以将手机屏幕映射到电脑上面!但是,由于演示时,是全屏的!
无法缩小,不好做演示!所以我才选择了360手机助手!
360手机助手下载地址:
注意:需要电脑和手机同时安装!使用电脑连接手机时,务必使用USB模式!因为演示模式时,只能使用USB!
默认华为P9,在设置里面开启USB之后,过一会就关闭了!怎么解决呢?进入工程菜单,开启USB才行!
详情,请参考链接:
https://club.huawei.com/thread-10239881-1-1.html
注意:先选择Google模式,再开启USB调试!
连接成功后,点击底部的小三角
右侧,会显示手机画面,比如:
打开HBuilder,连接自己的手机
运行之后,它会在你的手机上面,自动安装HBuilder的APP。并自动打开HBuilder,效果如下:
这里 没有加载图文列表,是因为 mui.js的IP不对。
修改mui.js,改为本机IP地址
window.ws_serv = "192.168.0.108:9528"; window.serv = "http://192.168.0.108:9527";
注意:请确保手机网络,能访问http://192.168.0.108:9528
有2个解决办法:
1. 电脑和手机连接同一wifi
2. 电脑开启wifi。wind10自带就有!用手机连接这个wifi即可!
请确保电脑的防火墙是关闭状态!打开控制面板-->系统和安全-->Windows Defender 防火墙。关闭防火墙!
关闭手机进程,再次访问,就可以了
重新登录一次,点击 管理我的玩具,效果如下:
点击添加按钮
它会跳转到 扫描二维码页面。看到中间的会动的红色线条没?说明它在识别中!
BarcodeSuccessCallback
扫码识别成功回调函数
说明:
当Barcode控件扫码成功时的回调函数,返回识别成功的扫码数据。
参数:
- type: ( Number ) 必选 识别到的条码类型
Number类型的值,与Barcode对象定义的条码类型常量一致。 - code: ( String ) 必选 识别到的条码数据
扫码识别出的数据内容,字符串类型,采用UTF8编码格式。 - file: ( String ) 可选 扫码成功的截图文件路径
扫码识别到的截图,png格式文件,如果设置为不保存截图,则返回undefined。
返回值:
void : 无
参考链接:
http://www.html5plus.org/doc/zh_cn/barcode.html#plus.barcode.BarcodeSuccessCallback
修改qrcdoe.html,增加回调函数
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">扫描玩具二维码</h1> </header> <div class="mui-content"> <div style="height: 550px;" id="qr"></div> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() function chenggong(type, code) { //扫码成功回调函数 mui.toast(code); // 显示二维码的内容 } mui.plusReady(function() { // 创建Barcode对象 var barcode = new plus.barcode.Barcode('qr'); barcode.start(); // 开始条码识别 barcode.onmarked = chenggong; // 扫码成功后,执行函数chenggong }) </script> </html>
进入flask项目,打开device_code目录。打开一张图片,使用真机,扫描一下二维码,效果如下:
二维码3种情况
用户扫描的二维码,有3种情况
1.当前设备根本不是我们授权生产的玩具 无效二维码 code=2
2.二维码有效,创建玩具,绑定用户 code=0
3.二维码有效,且已绑定用户,加好友 code=1
这3种情况,需要后端来校验!
进入flask项目,在serv目录下,新建一个文件devices.py
from flask import Blueprint, request, jsonify from setting import MONGO_DB from setting import RET from bson import ObjectId devs = Blueprint("devs", __name__) @devs.route("/yanzheng_qr", methods=["POST"]) def yanzheng_qr(): # 验证二维码 device_id = request.form.get("device_id") # 获取设备id if MONGO_DB.devices.find_one({"device_id": device_id}): # 从数据库中查询设备id # 查询该玩具是不是已被用户绑定 toy_info = MONGO_DB.toys.find_one({"device_id": device_id}) # 未绑定开启绑定逻辑 if not toy_info: RET["code"] = 0 RET["msg"] = "感谢购买本公司产品" RET["data"] = {} # 如果被绑定加好友逻辑开启 if toy_info: pass else: RET["code"] = 2 RET["msg"] = "二货,这不是本公司设备,快去买正版!" RET["data"] = {} return jsonify(RET)
修改 manager.py,注册蓝图
from flask import Flask, request,jsonify,render_template from setting import MONGO_DB from setting import RET from bson import ObjectId from serv import get_file from serv import content from serv import devices app = Flask(__name__) app.register_blueprint(get_file.getfile) app.register_blueprint(content.cont) app.register_blueprint(devices.devs) @app.route('/') def hello_world(): return render_template("index.html") @app.route('/login',methods=["POST"]) def login(): """ 登陆验证 :return: settings -> RET """ try: RET["code"] = 1 RET["msg"] = "用户名或密码错误" RET["data"] = {} username = request.form.get("username") password = request.form.get("password") user = MONGO_DB.users.find_one({"username": username, "password": password}) if user: # 由于user中的_id是ObjectId对象,需要转化为字符串 user["_id"] = str(user.get("_id")) RET["code"] = 0 RET["msg"] = "欢迎登陆" RET["data"] = {"user_id": user.get("_id")} except Exception as e: RET["code"] = 1 RET["msg"] = "登陆失败" return jsonify(RET) @app.route('/reg',methods=["POST"]) def reg(): """ 注册 :return: {"code":0,"msg":"","data":""} """ try: username = request.form.get("username") password = request.form.get("password") age = request.form.get("age") nickname = request.form.get("nickname") gender = request.form.get("gender") phone = request.form.get("phone") user_info = { "username": username, "password": password, "age": age, "nickname": nickname, # 判断gender==2,成立时为girl.jpg,否则为boy.jpg "avatar": "girl.jpg" if gender == 2 else "boy.jpg", "gender": gender, "phone": phone } res = MONGO_DB.users.insert_one(user_info) user_id = str(res.inserted_id) RET["code"] = 0 RET["msg"] = "注册成功" RET["data"] = user_id except Exception as e: RET["code"] = 1 RET["msg"] = "注册失败" return jsonify(RET) @app.route('/user_info', methods=["POST"]) def user_info(): user_id = request.form.get("user_id") # "password": 0 表示忽略密码字段 res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}, {"password": 0}) if res: res["_id"] = str(res.get("_id")) RET["code"] = 0 RET["msg"] = "" RET["data"] = res return jsonify(res) if __name__ == '__main__': app.run("0.0.0.0", 9527, debug=True)
重启 manager.py
进入HBuilder项目MyApp,修改qrcode.html,发送POST请求,将设备id发过去
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">扫描玩具二维码</h1> </header> <div class="mui-content"> <div style="height: 550px;" id="qr"></div> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() function chenggong(type, code) { //扫码成功回调函数 mui.post( // 验证二维码 window.serv + "/yanzheng_qr", { // 发送设备id device_id: code }, function(data) { console.log(JSON.stringify(data)); mui.toast(data.msg); //显示结果 } ) } mui.plusReady(function() { // 创建Barcode对象 var barcode = new plus.barcode.Barcode('qr'); barcode.start(); // 开始条码识别 barcode.onmarked = chenggong; // 扫码成功后,执行函数chenggong }) </script> </html>
先扫描一个冒牌的二维码
再来扫描一个正版的
修改 qrcode.html,判断3种情况。先写伪代码!
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">扫描玩具二维码</h1> </header> <div class="mui-content"> <div style="height: 550px;" id="qr"></div> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() function chenggong(type, code) { //扫码成功回调函数 mui.post( // 验证二维码 window.serv + "/yanzheng_qr", { // 发送设备id device_id: code }, function(data) { console.log(JSON.stringify(data)); mui.toast(data.msg); //显示结果 if(data.code == 2) { mui.back(); //返回页面 } if(data.code == 1) { //加好友的小逻辑 跳转到加好友页面 } if(data.code == 0) { //今天的逻辑 创建玩具 绑定用户 成为玩具的第一个好友 } } ) } mui.plusReady(function() { // 创建Barcode对象 var barcode = new plus.barcode.Barcode('qr'); barcode.start(); // 开始条码识别 barcode.onmarked = chenggong; // 扫码成功后,执行函数chenggong }) </script> </html>
三、创建玩具的基本属性
扫描成功后,需要跳转到绑定玩具页面!
新建文件bind_toy.html
bind_toy.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">绑定我的玩具</h1> </header> <div class="mui-content"> <form class="mui-input-group"> <div class="mui-input-row"> <label>玩具的昵称</label> <input type="text" class="mui-input-clear" placeholder="请输入玩具的昵称" id="toy_name"> </div> <div class="mui-input-row mui-radio mui-left"> <label>男</label> <input name="gender" type="radio" value="1"> </div> <div class="mui-input-row mui-radio mui-left"> <label>女</label> <input name="gender" type="radio" value="2" checked> </div> <div class="mui-input-row"> <label>玩具的主人</label> <input type="text" class="mui-input-clear" placeholder="请输入小主人的名字" id="baby_name"> </div> <div class="mui-input-row"> <label>主人的称呼</label> <input type="text" class="mui-input-clear" placeholder="玩具主人对您的称呼" id="remark"> </div> <div class="mui-button-row"> <button type="button" class="mui-btn mui-btn-primary" id="bind">绑定</button> <button type="button" class="mui-btn mui-btn-danger mui-action-back">取消</button> </div> </form> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() var Sdata = null; mui.plusReady(function() { Sdata = plus.webview.currentWebview(); }) </script> </html>
修改 qrcode.html,将设置id,传给bind_toy.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">扫描玩具二维码</h1> </header> <div class="mui-content"> <div style="height: 550px;" id="qr"></div> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() function chenggong(type, code) { //扫码成功回调函数 mui.post( // 验证二维码 window.serv + "/yanzheng_qr", { // 发送设备id device_id: code }, function(data) { console.log(JSON.stringify(data)); mui.toast(data.msg); //显示结果 if(data.code == 2) { mui.back(); //返回页面 } if(data.code == 1) { //加好友的小逻辑 跳转到加好友页面 } if(data.code == 0) { //今天的逻辑 创建玩具 绑定用户 成为玩具的第一个好友 //1.创建玩具:打开创建玩具的页面 mui.openWindow({ url:"bind_toy.html", id:"bind_toy.html", extras:{ device_id:code } }) } } ) } mui.plusReady(function() { // 创建Barcode对象 var barcode = new plus.barcode.Barcode('qr'); barcode.start(); // 开始条码识别 barcode.onmarked = chenggong; // 扫码成功后,执行函数chenggong }) </script> </html>
修改 bind_toy.html,将表单数据传给后端
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">绑定我的玩具</h1> </header> <div class="mui-content"> <form class="mui-input-group"> <div class="mui-input-row"> <label>玩具的昵称</label> <input type="text" class="mui-input-clear" placeholder="请输入玩具的昵称" id="toy_name"> </div> <div class="mui-input-row mui-radio mui-left"> <label>男</label> <input name="gender" type="radio" value="1"> </div> <div class="mui-input-row mui-radio mui-left"> <label>女</label> <input name="gender" type="radio" value="2" checked> </div> <div class="mui-input-row"> <label>玩具的主人</label> <input type="text" class="mui-input-clear" placeholder="请输入小主人的名字" id="baby_name"> </div> <div class="mui-input-row"> <label>主人的称呼</label> <input type="text" class="mui-input-clear" placeholder="玩具主人对您的称呼" id="remark"> </div> <div class="mui-button-row"> <button type="button" class="mui-btn mui-btn-primary" id="bind">绑定</button> <button type="button" class="mui-btn mui-btn-danger mui-action-back">取消</button> </div> </form> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() var Sdata = null; mui.plusReady(function() { Sdata = plus.webview.currentWebview(); console.log(plus.storage.getItem("user")) }) document.getElementById("bind").addEventListener("tap", function() { var toy_name = document.getElementById("toy_name").value; var baby_name = document.getElementById("baby_name").value; var remark = document.getElementById("remark").value; var gender_list = document.getElementsByName("gender"); var gender = null; for(var i = 0; i < gender_list.length; i++) { if(gender_list[i].checked) { gender = gender_list[i].value; } } mui.post( window.serv + "/bind_toy", { device_id: Sdata.device_id, toy_name:toy_name, baby_name:baby_name, remark:remark, gender:gender, // 全局变量,从plus.storage中获取 user_id:plus.storage.getItem("user") }, function(data){ console.log(JSON.stringify(data)); mui.toast(data.msg); } ) }) </script> </html>
bind_toy.html页面,效果是这个样子:
创建玩具的基本属性
进入flask项目,修改devices.py,新建一个视图函数bind_toy,用来绑定玩具
from flask import Blueprint, request, jsonify from setting import MONGO_DB from setting import RET from bson import ObjectId devs = Blueprint("devs", __name__) @devs.route("/yanzheng_qr", methods=["POST"]) def yanzheng_qr(): # 验证二维码 device_id = request.form.get("device_id") # 获取设备id if MONGO_DB.devices.find_one({"device_id": device_id}): # 从数据库中查询设备id # 查询该玩具是不是已被用户绑定 toy_info = MONGO_DB.toys.find_one({"device_id": device_id}) # 未绑定开启绑定逻辑 if not toy_info: RET["code"] = 0 RET["msg"] = "感谢购买本公司产品" RET["data"] = {} # 如果被绑定加好友逻辑开启 if toy_info: pass else: RET["code"] = 2 RET["msg"] = "二货,这不是本公司设备,快去买正版!" RET["data"] = {} return jsonify(RET) @devs.route("/bind_toy", methods=["POST"]) def bind_toy(): # 绑定玩具 device_id = request.form.get("device_id") # 设备id toy_name = request.form.get("toy_name") # 玩具的昵称 baby_name = request.form.get("baby_name") # 小主人的名字 remark = request.form.get("remark") # 玩具主人对您的称呼 gender = request.form.get("gender") # 性别 user_id = request.form.get("user_id") # 用户id res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}) # 查询用户id是否存在 toy_info = { "device_id": device_id, "toy_name": toy_name, "baby_name": baby_name, "gender": gender, "avatar": "boy.jpg" if gender == 1 else "girl.jpg", # 绑定用户 "bind_user": str(res.get("_id")), }
用户和玩具的绑定关系
玩具还有和APP进行通信,需要一个chat表,记录聊天id
修改 devices.py,修改 bind_toy视图函数
@devs.route("/bind_toy", methods=["POST"]) def bind_toy(): # 绑定玩具 chat_window = MONGO_DB.chat.insert_one({}) # 插入一个空数据 chat_id = chat_window.inserted_id # 获取聊天id user_id = request.form.get("user_id") # 用户id res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}) # 查询用户id是否存在 device_id = request.form.get("device_id") # 设备id toy_name = request.form.get("toy_name") # 玩具的昵称 baby_name = request.form.get("baby_name") # 小主人的名字 remark = request.form.get("remark") # 玩具主人对您的称呼 gender = request.form.get("gender") # 性别 toy_info = { "device_id": device_id, "toy_name": toy_name, "baby_name": baby_name, "gender": gender, "avatar": "boy.jpg" if gender == 1 else "girl.jpg", # 绑定用户 "bind_user": str(res.get("_id")), }
既然是聊天,需要有好友列表,并插入玩具表
修改 devices.py,修改 bind_toy视图函数
@devs.route("/bind_toy", methods=["POST"]) def bind_toy(): # 绑定玩具 chat_window = MONGO_DB.chat.insert_one({}) # 插入一个空数据 chat_id = chat_window.inserted_id # 获取聊天id user_id = request.form.get("user_id") # 用户id res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}) # 查询用户id是否存在 device_id = request.form.get("device_id") # 设备id toy_name = request.form.get("toy_name") # 玩具的昵称 baby_name = request.form.get("baby_name") # 小主人的名字 remark = request.form.get("remark") # 玩具主人对您的称呼 gender = request.form.get("gender") # 性别 toy_info = { "device_id": device_id, "toy_name": toy_name, "baby_name": baby_name, "gender": gender, "avatar": "boy.jpg" if gender == 1 else "girl.jpg", # 绑定用户 "bind_user": str(res.get("_id")), # 第一个好友 "friend_list": [{ "friend_id": str(res.get("_id")), # 好友id "friend_name": res.get("nickname"), # 好友昵称 "friend_remark": remark, # 好友称呼 "friend_avatar": res.get("avatar"), # 好友头像 "friend_chat": str(chat_id), # 好友聊天id }] } toy_res = MONGO_DB.toys.insert_one(toy_info) # 插入数据
用户难道只有一个好友吗?当然不是,他可以有很多个。
修改 devices.py,修改 bind_toy视图函数,做一个判断
@devs.route("/bind_toy", methods=["POST"]) def bind_toy(): # 绑定玩具 chat_window = MONGO_DB.chat.insert_one({}) # 插入一个空数据 chat_id = chat_window.inserted_id # 获取聊天id user_id = request.form.get("user_id") # 用户id res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}) # 查询用户id是否存在 device_id = request.form.get("device_id") # 设备id toy_name = request.form.get("toy_name") # 玩具的昵称 baby_name = request.form.get("baby_name") # 小主人的名字 remark = request.form.get("remark") # 玩具主人对您的称呼 gender = request.form.get("gender") # 性别 toy_info = { "device_id": device_id, "toy_name": toy_name, "baby_name": baby_name, "gender": gender, "avatar": "boy.jpg" if gender == 1 else "girl.jpg", # 绑定用户 "bind_user": str(res.get("_id")), # 第一个好友 "friend_list": [{ "friend_id": str(res.get("_id")), # 好友id "friend_name": res.get("nickname"), # 好友昵称 "friend_remark": remark, # 好友称呼 "friend_avatar": res.get("avatar"), # 好友头像 "friend_chat": str(chat_id), # 好友聊天id }] } toy_res = MONGO_DB.toys.insert_one(toy_info) # 插入玩具表数据 if res.get("friend_list"): # 判断用户好友列表是否为空 # 追加好友 res["bind_toy"].append(str(toy_res.inserted_id)) res["friend_list"].append({ "friend_id": str(toy_res.inserted_id), "friend_name": toy_name, "friend_remark": baby_name, "friend_avatar": toy_info.get("avatar"), "friend_chat": str(chat_id), }) else: # 更新好友 res["bind_toy"] = [str(toy_res.inserted_id)] res["friend_list"] = [{ "friend_id": str(toy_res.inserted_id), "friend_name": toy_name, "friend_remark": baby_name, "friend_avatar": toy_info.get("avatar"), "friend_chat": str(chat_id), }] MONGO_DB.users.update_one({"_id": ObjectId(user_id)}, {"$set": res}) # 更新用户记录
玩具通讯录中的第一个好友
那么 上面的chat_id是属于哪个用户的呢?需要更新chat表,做一个绑定!
修改 devices.py,修改 bind_toy视图函数。完整代码如下:
from flask import Blueprint, request, jsonify from setting import MONGO_DB from setting import RET from bson import ObjectId devs = Blueprint("devs", __name__) @devs.route("/yanzheng_qr", methods=["POST"]) def yanzheng_qr(): # 验证二维码 device_id = request.form.get("device_id") # 获取设备id if MONGO_DB.devices.find_one({"device_id": device_id}): # 从数据库中查询设备id # 查询该玩具是不是已被用户绑定 toy_info = MONGO_DB.toys.find_one({"device_id": device_id}) # 未绑定开启绑定逻辑 if not toy_info: RET["code"] = 0 RET["msg"] = "感谢购买本公司产品" RET["data"] = {} # 如果被绑定加好友逻辑开启 if toy_info: pass else: RET["code"] = 2 RET["msg"] = "二货,这不是本公司设备,快去买正版!" RET["data"] = {} return jsonify(RET) @devs.route("/bind_toy", methods=["POST"]) def bind_toy(): # 绑定玩具 chat_window = MONGO_DB.chat.insert_one({}) # 插入一个空数据 chat_id = chat_window.inserted_id # 获取聊天id user_id = request.form.get("user_id") # 用户id res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}) # 查询用户id是否存在 device_id = request.form.get("device_id") # 设备id toy_name = request.form.get("toy_name") # 玩具的昵称 baby_name = request.form.get("baby_name") # 小主人的名字 remark = request.form.get("remark") # 玩具主人对您的称呼 gender = request.form.get("gender") # 性别 toy_info = { "device_id": device_id, "toy_name": toy_name, "baby_name": baby_name, "gender": gender, "avatar": "boy.jpg" if gender == 1 else "girl.jpg", # 绑定用户 "bind_user": str(res.get("_id")), # 第一个好友 "friend_list": [{ "friend_id": str(res.get("_id")), # 好友id "friend_name": res.get("nickname"), # 好友昵称 "friend_remark": remark, # 好友称呼 "friend_avatar": res.get("avatar"), # 好友头像 "friend_chat": str(chat_id), # 好友聊天id }] } toy_res = MONGO_DB.toys.insert_one(toy_info) # 插入玩具表数据 if res.get("friend_list"): # 判断用户好友列表是否为空 # 追加好友 res["bind_toy"].append(str(toy_res.inserted_id)) res["friend_list"].append({ "friend_id": str(toy_res.inserted_id), "friend_name": toy_name, "friend_remark": baby_name, "friend_avatar": toy_info.get("avatar"), "friend_chat": str(chat_id), }) else: # 更新好友 res["bind_toy"] = [str(toy_res.inserted_id)] res["friend_list"] = [{ "friend_id": str(toy_res.inserted_id), "friend_name": toy_name, "friend_remark": baby_name, "friend_avatar": toy_info.get("avatar"), "friend_chat": str(chat_id), }] MONGO_DB.users.update_one({"_id": ObjectId(user_id)}, {"$set": res}) # 更新用户记录 # 更新聊天表 # user_list有2个值。第一个是玩具id,第2个是用户id # 这样,用户和玩具就能通讯了 MONGO_DB.chat.update_one({"_id": chat_id}, {"$set": {"user_list": [str(toy_res.inserted_id), str(res.get("_id"))]}}) RET["code"] = 0 RET["msg"] = "绑定成功" RET["data"] = {} return jsonify(RET)
重启 manager.py
使用手机扫描正版的二维码。它会跳转到这个页面
填写相关信息
点击绑定,页面底部提示:绑定成功!
先来查看用户表,会发现有一个id
在看下面的好友列表
看聊天表,只有一条记录
看玩具表,只有一条记录
看下面的好友列表
绑定完成之后,需要跳转页面。跳转到哪里呢?跳转到 toy_manager.html页面
这个页面,需要加载当前登录用户的玩具
修改toy_manager.html,发送post请求
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">管理我的玩具</h1> </header> <div class="mui-content"> <ul class="mui-table-view" id="toy_list"> <li class="mui-table-view-cell mui-media"> <a id="add_toy"> <img class="mui-media-object mui-pull-left" src="images/add.png"> <div class="mui-media-body"> 你还没有玩具 <p class="mui-ellipsis">点击此处扫描二维码添加玩具</p> </div> </a> </li> </ul> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init(); mui.plusReady(function(){ // 发送POST请求,访问玩具列表 mui.post( window.serv + "/toy_list", {user_id:plus.storage.getItem("user")}, function(data){ console.log(JSON.stringify(data)); } ) }); document.getElementById("add_toy").addEventListener("tap", function() { mui.openWindow({ url: "qrcode.html", id: "qrcode.html", }) }); </script> </html>
进入flask后端,在serv目录下,新建文件 toys.py
from flask import Blueprint, request, jsonify from setting import MONGO_DB from setting import RET from bson import ObjectId toy = Blueprint("toy", __name__) @toy.route("/toy_list", methods=["POST"]) def toy_list(): # 玩具列表 user_id = request.form.get("user_id") # 用户id # 查看用户信息 user_info = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}) bind_toy = user_info.get("bind_toy") # 获取绑定的玩具 bind_toy_id = [] # 玩具列表 for toy_id in bind_toy: # 获取玩具列表中的所有玩具id bind_toy_id.append(ObjectId(toy_id)) # 一次性查询多个玩具 toys_list = list(MONGO_DB.toys.find({"_id": {"$in": bind_toy_id}})) for index,item in enumerate(toys_list): # 将_id转换为字符串 toys_list[index]["_id"] = str(item.get("_id")) RET["code"] = 0 RET["msg"] = "" RET["data"] = toys_list return jsonify(RET)
修改manager.py,注册蓝图
from flask import Flask, request,jsonify,render_template from setting import MONGO_DB from setting import RET from bson import ObjectId from serv import get_file from serv import content from serv import devices from serv import toys app = Flask(__name__) app.register_blueprint(get_file.getfile) app.register_blueprint(content.cont) app.register_blueprint(devices.devs) app.register_blueprint(toys.toy) @app.route('/') def hello_world(): return render_template("index.html") @app.route('/login',methods=["POST"]) def login(): """ 登陆验证 :return: settings -> RET """ try: RET["code"] = 1 RET["msg"] = "用户名或密码错误" RET["data"] = {} username = request.form.get("username") password = request.form.get("password") user = MONGO_DB.users.find_one({"username": username, "password": password}) if user: # 由于user中的_id是ObjectId对象,需要转化为字符串 user["_id"] = str(user.get("_id")) RET["code"] = 0 RET["msg"] = "欢迎登陆" RET["data"] = {"user_id": user.get("_id")} except Exception as e: RET["code"] = 1 RET["msg"] = "登陆失败" return jsonify(RET) @app.route('/reg',methods=["POST"]) def reg(): """ 注册 :return: {"code":0,"msg":"","data":""} """ try: username = request.form.get("username") password = request.form.get("password") age = request.form.get("age") nickname = request.form.get("nickname") gender = request.form.get("gender") phone = request.form.get("phone") user_info = { "username": username, "password": password, "age": age, "nickname": nickname, # 判断gender==2,成立时为girl.jpg,否则为boy.jpg "avatar": "girl.jpg" if gender == 2 else "boy.jpg", "gender": gender, "phone": phone } res = MONGO_DB.users.insert_one(user_info) user_id = str(res.inserted_id) RET["code"] = 0 RET["msg"] = "注册成功" RET["data"] = user_id except Exception as e: RET["code"] = 1 RET["msg"] = "注册失败" return jsonify(RET) @app.route('/user_info', methods=["POST"]) def user_info(): user_id = request.form.get("user_id") # "password": 0 表示忽略密码字段 res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}, {"password": 0}) if res: res["_id"] = str(res.get("_id")) RET["code"] = 0 RET["msg"] = "" RET["data"] = res return jsonify(res) if __name__ == '__main__': app.run("0.0.0.0", 9527, debug=True)
直接访问管理我的玩具页面,它会发起POST请求
查看HBuilder控制台输出:
{"code":0,"data":[{"_id":"5ba0f1f2e12532418089bf88","avatar":"girl.jpg","baby_name":"小甜甜","bind_user":"5b9bb768e1253281608e96eb","device_id":"01f9bf1bac93eddd8397d0455abbeddb","friend_list":[{"friend_avatar":"boy.jpg","friend_chat":"5ba0f1f2e12532418089bf87","friend_id":"5b9bb768e1253281608e96eb","friend_name":"xiao","friend_remark":"小鱼"}],"gender":"2","toy_name":"小可爱"}],"msg":""} at toy_manager.html:39
那么拿到数据了,就可以渲染页面了!
修改 toy_manager.html,渲染ul标签
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">管理我的玩具</h1> </header> <div class="mui-content"> <ul class="mui-table-view" id="toy_list"> <li class="mui-table-view-cell mui-media"> <a id="add_toy"> <img class="mui-media-object mui-pull-left" src="images/add.png"> <div class="mui-media-body"> 你还没有玩具 <p class="mui-ellipsis">点击此处扫描二维码添加玩具</p> </div> </a> </li> </ul> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init(); mui.plusReady(function(){ // 发送POST请求,访问玩具列表 mui.post( window.serv + "/toy_list", {user_id:plus.storage.getItem("user")}, function(data){ console.log(JSON.stringify(data)); // for循环玩具列表 for (var i = 0; i < data.data.length; i++) { // 调用自定义函数,渲染玩具列表 create_content(data.data[i]); } } ) }); function create_content(content) { //玩具列表 var litag = document.createElement("li"); litag.className = "mui-table-view-cell mui-media"; var atag = document.createElement("a"); atag.id = content._id; atag.onclick = function() { console.log(this.id); //openPlayer(this.id); } var imgtag = document.createElement("img"); imgtag.className = "mui-media-object mui-pull-left"; imgtag.style = "border-radius: 50%;width: 45px;height: 45px; " imgtag.src = "avatar/" + content.avatar; var divtag = document.createElement("div"); divtag.className = "mui-media-body"; divtag.innerText = content.baby_name; var ptag = document.createElement("p"); ptag.className = "mui-ellipsis"; ptag.innerText = content.toy_name; litag.appendChild(atag); atag.appendChild(imgtag); atag.appendChild(divtag); divtag.appendChild(ptag); document.getElementById("toy_list").appendChild(litag); } document.getElementById("add_toy").addEventListener("tap", function() { mui.openWindow({ url: "qrcode.html", id: "qrcode.html", }) }); </script> </html>
重新访问 管理我的玩具页面,效果如下:
这里有一个坑,绑定玩具之后,不要跳转到 管理我的玩具页面!它有可能会加载失败
修改bind_toy.html,跳转改为user_info页面
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link rel="stylesheet" type="text/css" href="css/mui.css" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">绑定我的玩具</h1> </header> <div class="mui-content"> <form class="mui-input-group"> <div class="mui-input-row"> <label>玩具的昵称</label> <input type="text" class="mui-input-clear" placeholder="请输入玩具的昵称" id="toy_name"> </div> <div class="mui-input-row mui-radio mui-left"> <label>男</label> <input name="gender" type="radio" value="1"> </div> <div class="mui-input-row mui-radio mui-left"> <label>女</label> <input name="gender" type="radio" value="2" checked> </div> <div class="mui-input-row"> <label>玩具的主人</label> <input type="text" class="mui-input-clear" placeholder="请输入小主人的名字" id="baby_name"> </div> <div class="mui-input-row"> <label>主人的称呼</label> <input type="text" class="mui-input-clear" placeholder="玩具主人对您的称呼" id="remark"> </div> <div class="mui-button-row"> <button type="button" class="mui-btn mui-btn-primary" id="bind">绑定</button> <button type="button" class="mui-btn mui-btn-danger mui-action-back">取消</button> </div> </form> </div> </body> <script src="js/mui.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init() var Sdata = null; mui.plusReady(function() { Sdata = plus.webview.currentWebview(); console.log(plus.storage.getItem("user")) }) document.getElementById("bind").addEventListener("tap", function() { var toy_name = document.getElementById("toy_name").value; var baby_name = document.getElementById("baby_name").value; var remark = document.getElementById("remark").value; var gender_list = document.getElementsByName("gender"); var gender = null; for(var i = 0; i < gender_list.length; i++) { if(gender_list[i].checked) { gender = gender_list[i].value; } } mui.post( window.serv + "/bind_toy", { device_id: Sdata.device_id, toy_name:toy_name, baby_name:baby_name, remark:remark, gender:gender, // 全局变量,从plus.storage中获取 user_id:plus.storage.getItem("user") }, function(data){ console.log(JSON.stringify(data)); mui.toast(data.msg); // 绑定玩具成功之后 if(data.code==0){ // 跳转到用户信息页面 mui.openWindow({ url:"user_info.html", id:"user_info.html", styles:window.styles }) } } ) }) </script> </html>
今日总结:
1.创建二维码 device_id = f"{uuid4()}{time.time()}" device_id_md5 = hashlib.md5(device_id.encode("utf8")) requests.get("http://qr.liantu.com/api.php?text=%s" %(device_id_md5)) 2.扫码 var barcode = new plus.barcode.Barcode('qr'); 创建HTML5PLUS的Barcode扫码对象 var barcode = plus.barcode.create('qr',[plus.barcode.QR],sytles={top,left,weith,heigh}) 创建完成之后还得webview.append 1.当前设备根本不是我们授权生产的玩具 无效二维码 2 2.二维码有效,创建玩具,绑定用户 0 3.二维码有效,且已绑定用户,加好友 1 3.创建玩具的基本属性 toy_info = { "device_id": device_id, "toy_name": toy_name, "baby_name": baby_name, "gender": gender, "avatar": "boy.jpg" if gender == 1 else "girl.jpg", "bind_user":str(res.get("_id")) } 玩具还要和 APP 进行通讯 ,chat chat_id 详见代码 4.用户和玩具的绑定关系 用户添加玩具为好友和绑定关系 详见代码 5.玩具通讯录中的第一个好友 详见代码 刚刚开机的时候: 1.授权问题(MD5授权码)提示语 : 请联系玩具厂商 2.绑定问题 提示语 : 快给我找一个小主人 3.成功 提示语:欢迎使用
完整代码,请参考github:
https://github.com/987334176/Intelligent_toy/archive/v1.2.zip