一、玩具开机提示语

先下载github代码,下面的操作,都是基于这个版本来的!

https://github.com/987334176/Intelligent_toy/archive/v1.2.zip

注意:由于涉及到版权问题,此附件没有图片和音乐。请参考链接,手动采集一下!

请参考链接:

https://www.cnblogs.com/xiao987334176/p/9647993.html#autoid-3-4-0

判断设备id

每一个玩具,都有设备id。如果在设备表中,提示找小主人。否则提示 联系厂家。

如果在玩具表中,提示开机!

进入flask项目,将jquery.min.js下载到static目录,下载链接如下:

https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js

使用jquery的原因,是因为要发送ajax的POST请求。使用$.post{}

修改 templates-->index.html,增加开机按钮

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> </head>
<body>
<audio src="" autoplay="autoplay" controls id="player"></audio>
<br>
<input type="text" id="device_id">
<button onclick="start_toy()">玩具开机键</button>
<br>
<button onclick="start_reco()">开始废话</button>
<br>
<button onclick="stop_reco()">发送语音</button>
</body>
<script src="/static/recorder.js"></script>
<script src="/static/jquery.min.js"></script>
<script type="application/javascript">
// 获取音频文件
var get_file = "http://192.168.11.24:9527/get_audio/";
// 创建 WebSocket 对象
var ws = new WebSocket("ws://192.168.11.24:9528/toy/123456");
var reco = null;
// 创建AudioContext对象
var audio_context = new AudioContext();
//要获取音频和视频
navigator.getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia); // 拿到媒体对象,允许音频对象
navigator.getUserMedia({audio: true}, create_stream, function (err) {
console.log(err)
}); //创建媒体流容器
function create_stream(user_media) {
var stream_input = audio_context.createMediaStreamSource(user_media);
// 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流
reco = new Recorder(stream_input); } function start_reco() { //开始录音
reco.record(); //往里面写流
} function stop_reco() { //停止录音
reco.stop(); //停止写入流
get_audio(); //调用自定义方法
reco.clear(); //清空容器
} function get_audio() { // 获取音频
reco.exportWAV(function (wav_file) {
ws.send(wav_file); //使用websocket连接发送数据给后端
})
} ws.onmessage = function (data) { // 客户端接收服务端数据时触发
// console.log(get_file + data.data);
var content = JSON.parse(data.data);
console.log(content);
// 修改id为player的src属性,实现自动播放
document.getElementById("player").src = get_file + content.data;
console.log(content.from_user + "给你点了一首歌");
}; function start_toy() { // 玩具开机
// 获取输入的设备id
var device_id = document.getElementById("device_id").value;
// 发送post请求
$.post(
// 这里的地址必须是127.0.0.1,否则会有跨域问题
"http://127.0.0.1:9527/device_toy_id",
// 发送设备id
{device_id: device_id},
function (data) {
console.log(data);
}, "json"
// 规定预期的服务器响应的数据类型为json
);
} </script>
</html>

修改 serv-->toys.py,增加视图函数device_toy_id

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) @toy.route("/device_toy_id", methods=["POST"])
def device_toy_id():
device_id = request.form.get("device_id") # 获取设备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 toy_info:
return jsonify("开机")
else:
# 已授权的设备,但是没有绑定主人
return jsonify("找小主人")
else:
# 不在设备表中,说明是未授权,或者是冒牌的!
return jsonify("联系玩具厂")

重启 manager.py,访问首页

输入一段数字,点击玩具开机键,效果如下:

打开 MongoDB客户端,复制一个不在玩具表(toys)中的设备id。效果如下:

复制一个,在玩具表中的设备id,效果如下:

提示语

后端逻辑判断,大致搞定了。下面来录制提示语,这里使用百度ai的接口。

在项目根目录,新建目录utils,在此目录下新建baidu_ai.py

此时,目录结构如下:

./
├── audio
├── audio_img
├── device_code
├── im_serv.py
├── manager.py
├── QRcode.py
├── serv
│   ├── content.py
│   ├── devices.py
│   ├── get_file.py
│   └── toys.py
├── setting.py
├── static
│   ├── jquery.min.js
│   └── recorder.js
├── templates
│   └── index.html
├── utils
│   └── baidu_ai.py
└── xiaopapa.py

修改 setting.py,增加百度AI的秘钥。注意:后5位被我修改了,请改为自己的!

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") # 二维码 # 百度AI配置
APP_ID = ""
API_KEY = "3v3igzCkVFUDwFByNEE12345"
SECRET_KEY = "jRnwLE7kzC1aRi2FD10OQY3y9Og12345"
SPEECH = {
"spd": 4,
'vol': 5,
"pit": 8,
"per": 4
}

修改 baidu_ai.py,录制开机语音

from aip import AipSpeech
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 项目根目录 import sys
sys.path.append(BASE_DIR) # 加入到系统环境变量中 import setting # 导入setting client = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY) res = client.synthesis("欢迎来到嘉禾智能亲子互动乐园","zh",1,setting.SPEECH) with open(os.path.join(setting.AUDIO_FILE,"success.mp3"),"wb") as f:
f.write(res)

执行 baidu_ai.py,会在audio目录生成 success.mp3 文件。试听一下,感觉萌萌哒!

注意:语言文件的保存路径是audio。为什么呢?因为前端会调用get_audio接口。它是从audio目录读取的!

修改 baidu_ai.py,录制没有小主人语音

from aip import AipSpeech
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 项目根目录 import sys
sys.path.append(BASE_DIR) # 加入到系统环境变量中 import setting # 导入setting client = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY) res = client.synthesis("亲,我还没有小主人,快帮我找一个吧","zh",1,setting.SPEECH) with open(os.path.join(setting.AUDIO_FILE,"Nobind.mp3"),"wb") as f:
f.write(res)

执行 baidu_ai.py,会在audio目录生成 Nobind.mp3 文件。试听一下吧

修改 baidu_ai.py,录制联系玩具厂商语音

from aip import AipSpeech
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 项目根目录 import sys
sys.path.append(BASE_DIR) # 加入到系统环境变量中 import setting # 导入setting client = AipSpeech(setting.APP_ID,setting.API_KEY,setting.SECRET_KEY) res = client.synthesis("硬件设备不符,请联系玩具厂商","zh",1,setting.SPEECH) with open(os.path.join(setting.AUDIO_FILE,"Nodevice.mp3"),"wb") as f:
f.write(res)

执行 baidu_ai.py,会在audio目录生成 Nodevice.mp3 文件。试听一下吧

修改 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) @toy.route("/device_toy_id", methods=["POST"])
def device_toy_id(): # 验证设备id
RET["code"] = 0
RET["msg"] = "开机成功"
RET["data"] = {} device_id = request.form.get("device_id") # 获取设备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 toy_info:
# RET添加键值,获取玩具id
RET["data"]["toy_id"] = str(toy_info.get("_id"))
# 音频文件
RET["data"]["audio"] = "success.mp3"
return jsonify(RET)
else:
# 已授权的设备,但是没有绑定主人
RET["msg"] = "找小主人"
RET["data"]["audio"] = "Nobind.mp3"
return jsonify(RET)
else:
# 不在设备表中,说明是未授权,或者是冒牌的!
RET["msg"] = "联系玩具厂"
RET["data"]["audio"] = "Nodevice.mp3"
return jsonify(RET)

修改 index.html,POST请求成功后,修改audio标签的文件路径。将ws.onmessage代码移植到下面!

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> </head>
<body>
<audio src="" autoplay="autoplay" controls id="player"></audio>
<br>
<input type="text" id="device_id">
<button onclick="start_toy()">玩具开机键</button>
<br>
<button onclick="start_reco()">开始废话</button>
<br>
<button onclick="stop_reco()">发送语音</button>
</body>
<script src="/static/recorder.js"></script>
<script src="/static/jquery.min.js"></script>
<script type="application/javascript">
// 获取音频文件
var get_file = "http://192.168.11.24:9527/get_audio/"; var ws = null; // WebSocket 对象
var reco = null;
// 创建AudioContext对象
var audio_context = new AudioContext();
//要获取音频和视频
navigator.getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia); // 拿到媒体对象,允许音频对象
navigator.getUserMedia({audio: true}, create_stream, function (err) {
console.log(err)
}); //创建媒体流容器
function create_stream(user_media) {
var stream_input = audio_context.createMediaStreamSource(user_media);
// 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流
reco = new Recorder(stream_input); } function start_reco() { //开始录音
reco.record(); //往里面写流
} function stop_reco() { //停止录音
reco.stop(); //停止写入流
get_audio(); //调用自定义方法
reco.clear(); //清空容器
} function get_audio() { // 获取音频
reco.exportWAV(function (wav_file) {
ws.send(wav_file); //使用websocket连接发送数据给后端
})
} function start_toy() { // 玩具开机
// 获取输入的设备id
var device_id = document.getElementById("device_id").value;
// 发送post请求
$.post(
// 这里的地址必须是127.0.0.1,否则会有跨域问题
"http://127.0.0.1:9527/device_toy_id",
// 发送设备id
{device_id: device_id},
function (data) {
console.log(data);
toy_id = data.data.toy_id; // 玩具id
// 修改audio标签的src属性
document.getElementById("player").src = get_file + data.data.audio;
if (toy_id) { // 判断玩具id存在时
ws = new WebSocket("ws://192.168.11.24:9528/toy/" + toy_id);
ws.onmessage = function (data) {
// console.log(get_file + data.data);
var content = JSON.parse(data.data); //反序列化数据
document.getElementById("player").src = get_file + content.data;
console.log(content.from_user + "给你点了一首歌");
}
}
}, "json"
// 规定预期的服务器响应的数据类型为json
);
} </script>
</html>

重启 manager.py,访问首页,输入正确的设备id,效果如下:

这个功能,还可以扩展。比如判断今天是否为小主人的生日。说:生日快乐!

或者阳历节日,也可以提醒!

二、为多个玩具发送点播

用户有一个玩具,或者多个玩具时。
如果点击这个按钮,需要用户选择,指定发送给哪一个玩具。

目前数据库中,只有一个用户。昨天已经添加了一个,具体操作,请从参考昨天的链接:

https://www.cnblogs.com/xiao987334176/p/9670063.html

现在再来添加一个!

绑定成功后,查看玩具表。有2条记录了

查看用户表,查看好友字段,会有2个!

建立连接

开2个页面,表示2个玩具。让2个玩具开机,需要2个合格的设备id。

打开玩具表,复制2个设备id

打开2个网页,左边输入 嘻嘻 的设备id

右边输入 小可爱 的设备id

在Console中,输入ws,回车。会出现一个websocket链接

注意:只要玩具开机了,就会建立 websocket连接!

查看Pycharm控制台输出:此时应该有2个websocket连接:

{'5ba21c84e1253229c4acbd12': <geventwebsocket.websocket.WebSocket object at 0x000002DB8812BE18>, '5ba0f1f2e12532418089bf88': <geventwebsocket.websocket.WebSocket object at 0x000002DB88172590>}

那么APP页面,如何选择多个玩具呢?需要用到 弹出菜单

弹出菜单

mui框架内置了弹出菜单插件,弹出菜单显示内容不限,但必须包裹在一个含.mui-popover类的div中,如下即为一个弹出菜单内容:

<div id="popover" class="mui-popover">
<ul class="mui-table-view">
<li class="mui-table-view-cell"><a href="#">Item1</a></li>
<li class="mui-table-view-cell"><a href="#">Item2</a></li>
<li class="mui-table-view-cell"><a href="#">Item3</a></li>
<li class="mui-table-view-cell"><a href="#">Item4</a></li>
<li class="mui-table-view-cell"><a href="#">Item5</a></li>
</ul>
</div>

要显示、隐藏如上菜单,mui推荐使用锚点方式,例如:

<a href="#popover" id="openPopover" class="mui-btn mui-btn-primary mui-btn-block">打开弹出菜单</a>

点击如上定义的按钮,即可显示弹出菜单,再次点击弹出菜单之外的其他区域,均可关闭弹出菜单;这种使用方式最为简洁。

若希望通过js的方式控制弹出菜单,则通过如下一个方法即可:

mui('.bottomPopover').popover(status[,anchor]);

status

  • 'show'
    显示popover
  • 'hide'
    隐藏popover
  • 'toggle'
    自动识别处理显示隐藏状态
mui('.bottomPopover').popover('toggle');//show hide toggle

本文参考链接:

http://dev.dcloud.net.cn/mui/ui/#ui_popover

修改 player.html,只修改html代码部分,js代码不用动!

<!doctype html>
<html> <head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="css/mui.min.css" rel="stylesheet" />
</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" id="title_text">正在播放</h1>
</header>
<div class="mui-content">
<div class="mui-row" style="text-align: center;margin-top: 5px;">
<img src="avatar/girl.jpg" style="width: 250px;height: 250px; border-radius: 50%;" id="avatar" />
</div>
<button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="play">播放</button>
<button type="button" class="mui-btn mui-btn-yellow mui-btn-block" id="pause">暂停</button>
<button type="button" class="mui-btn mui-btn-green mui-btn-block" id="resume">继续</button>
<button type="button" class="mui-btn mui-btn-red mui-btn-block" id="stop">停止</button>
<style type="text/css">
#popover {
height: 150px;
width: 300px;
}
</style>
<div id="popover" class="mui-popover">
<div class="mui-scroll-wrapper">
<div class="mui-scroll">
<ul class="mui-table-view" id="toy_list" style="text-align: center;">
<li class="mui-table-view-cell"><a href="#">Item1</a></li>
<li class="mui-table-view-cell"><a href="#">Item2</a></li>
</ul>
</div>
</div>
</div>
<!--<button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="send2toy">发送给玩具</button>-->
<a href="#popover" id="openPopover" class="mui-btn mui-btn-primary mui-btn-block">发送给玩具</a>
</div> </body>
<script src="js/mui.js"></script>
<script type="text/javascript">
mui.init();
var Sdata = null; //当前web页面
var music_name = null; //歌曲名
var player = null; //播放对象
mui.plusReady(function() {
Sdata = plus.webview.currentWebview(); // 当前web页面
mui.toast(Sdata.content_id); // 弹窗显示由main.html传递的content_id //发送post请求
mui.post(
window.serv + "/content_one", {
// 参数为content_id
content_id: Sdata.content_id
},
function(data) {
// 打印响应数据
console.log(JSON.stringify(data));
// 修改标题
document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
// 修改图片地址
document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
// 调用自定义方法,播放音频
// data是后端返回的数据,data.audio是音频文件名
music_name = data.data.audio; // 歌曲名
play_anything(music_name); //播放歌曲
}
); function play_anything(content) { //播放音频
// 创建播放对象,拼接路径
player = plus.audio.createPlayer(window.serv_audio + content);
console.log(window.serv_audio + content); //打印路径
// http://192.168.11.86:9527/get_audio/a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3
player.play(); // 播放音频
} document.getElementById("play").addEventListener("tap", function() {
player.play();
}); document.getElementById("pause").addEventListener("tap", function() {
player.pause(); //暂停
}); document.getElementById("resume").addEventListener("tap", function() {
player.resume(); //继续
}); document.getElementById("stop").addEventListener("tap", function() {
player.stop(); // 停止,直接清空player中的对象
}); //发送给玩具
document.getElementById("send2toy").addEventListener("tap", function() {
var index = plus.webview.getWebviewById("HBuilder"); //index.html页面
mui.fire(index, "send_music", { //发送音乐
music_name: music_name, //歌曲名
toy_id:"" // 发给玩具id为12345
})
}); })
</script> </html>

使用模拟器访问,点击 发送给玩具,效果如下:

上面的item固定死了,需要展示为当前用户的 玩具名。需要访问后端接口,查询当前用户的所有玩具

修改 player.html

<!doctype html>
<html> <head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="css/mui.min.css" rel="stylesheet" />
</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" id="title_text">正在播放</h1>
</header>
<div class="mui-content">
<div class="mui-row" style="text-align: center;margin-top: 5px;">
<img src="avatar/girl.jpg" style="width: 250px;height: 250px; border-radius: 50%;" id="avatar" />
</div>
<button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="play">播放</button>
<button type="button" class="mui-btn mui-btn-yellow mui-btn-block" id="pause">暂停</button>
<button type="button" class="mui-btn mui-btn-green mui-btn-block" id="resume">继续</button>
<button type="button" class="mui-btn mui-btn-red mui-btn-block" id="stop">停止</button>
<style type="text/css">
#popover {
height: 150px;
width: 300px;
}
</style>
<div id="popover" class="mui-popover">
<div class="mui-scroll-wrapper">
<div class="mui-scroll">
<ul class="mui-table-view" id="toy_list" style="text-align: center;"> </ul>
</div>
</div>
</div>
<!--<button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="send2toy">发送给玩具</button>-->
<a href="#popover" id="openPopover" class="mui-btn mui-btn-primary mui-btn-block">发送给玩具</a>
</div> </body>
<script src="js/mui.js"></script>
<script type="text/javascript">
mui.init();
var Sdata = null; //当前web页面
var music_name = null; //歌曲名
var player = null; //播放对象
mui.plusReady(function() {
Sdata = plus.webview.currentWebview(); // 当前web页面
mui.toast(Sdata.content_id); // 弹窗显示由main.html传递的content_id //发送post请求
mui.post(
window.serv + "/content_one", {
// 参数为content_id
content_id: Sdata.content_id
},
function(data) {
// 打印响应数据
console.log(JSON.stringify(data));
// 修改标题
document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
// 修改图片地址
document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
// 调用自定义方法,播放音频
// data是后端返回的数据,data.audio是音频文件名
music_name = data.data.audio; // 歌曲名
play_anything(music_name); //播放歌曲
}
); mui.post( //查询当前用户的玩具列表
window.serv + "/toy_list", {
user_id: plus.storage.getItem("user")
},
function(data) {
console.log(JSON.stringify(data));
for(var i = 0; i < data.data.length; i++) {
// 执行定义方法create_toy,增加li标签
create_toy(data.data[i]);
} }
); function play_anything(content) { //播放音频
// 创建播放对象,拼接路径
player = plus.audio.createPlayer(window.serv_audio + content);
console.log(window.serv_audio + content); //打印路径
// http://192.168.11.86:9527/get_audio/a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3
player.play(); // 播放音频
} document.getElementById("play").addEventListener("tap", function() {
player.play();
}); document.getElementById("pause").addEventListener("tap", function() {
player.pause(); //暂停
}); document.getElementById("resume").addEventListener("tap", function() {
player.resume(); //继续
}); document.getElementById("stop").addEventListener("tap", function() {
player.stop(); // 停止,直接清空player中的对象
}); //发送给玩具
document.getElementById("send2toy").addEventListener("tap", function() {
var index = plus.webview.getWebviewById("HBuilder"); //index.html页面
mui.fire(index, "send_music", { //发送音乐
music_name: music_name, //歌曲名
toy_id: "" // 发给玩具id为12345
})
}); function create_toy(toy_info) { // 创建玩具
// 构造下面的标签
// <li class="mui-table-view-cell">
// <a href="#">Item1</a>
// </li>
var litag = document.createElement("li");
litag.className = "mui-table-view-cell"
var atag = document.createElement("a");
atag.id = toy_info._id;
atag.innerText = toy_info.baby_name; litag.appendChild(atag);
document.getElementById("toy_list").appendChild(litag);
} })
</script> </html>

重新访问一次,效果如下:

点击 小豆芽 是没有效果的!需要增加点击事件。由于它是a标签,使用onclick

需要使用websocket发送数据。由于index.html建立了websocket连接,使用fire事件将数据发给index.html。

由index.html来发送数据!

修改player.html

<!doctype html>
<html> <head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="css/mui.min.css" rel="stylesheet" />
</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" id="title_text">正在播放</h1>
</header>
<div class="mui-content">
<div class="mui-row" style="text-align: center;margin-top: 5px;">
<img src="avatar/girl.jpg" style="width: 250px;height: 250px; border-radius: 50%;" id="avatar" />
</div>
<button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="play">播放</button>
<button type="button" class="mui-btn mui-btn-yellow mui-btn-block" id="pause">暂停</button>
<button type="button" class="mui-btn mui-btn-green mui-btn-block" id="resume">继续</button>
<button type="button" class="mui-btn mui-btn-red mui-btn-block" id="stop">停止</button>
<!--弹窗样式-->
<style type="text/css">
#popover {
height: 150px;
width: 300px;
}
</style>
<div id="popover" class="mui-popover">
<div class="mui-scroll-wrapper">
<div class="mui-scroll">
<ul class="mui-table-view" id="toy_list" style="text-align: center;"> </ul>
</div>
</div>
</div>
<!--<button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="send2toy">发送给玩具</button>-->
<a href="#popover" id="openPopover" class="mui-btn mui-btn-primary mui-btn-block">发送给玩具</a>
</div> </body>
<script src="js/mui.js"></script>
<script type="text/javascript">
mui.init();
var Sdata = null; //当前web页面
var music_name = null; //歌曲名
var player = null; //播放对象
mui.plusReady(function() {
Sdata = plus.webview.currentWebview(); // 当前web页面
mui.toast(Sdata.content_id); // 弹窗显示由main.html传递的content_id //发送post请求
mui.post(
window.serv + "/content_one", {
// 参数为content_id
content_id: Sdata.content_id
},
function(data) {
// 打印响应数据
console.log(JSON.stringify(data));
// 修改标题
document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
// 修改图片地址
document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
// 调用自定义方法,播放音频
// data是后端返回的数据,data.audio是音频文件名
music_name = data.data.audio; // 歌曲名
play_anything(music_name); //播放歌曲
}
); mui.post( //查询当前用户的玩具列表
window.serv + "/toy_list", {
user_id: plus.storage.getItem("user")
},
function(data) {
console.log(JSON.stringify(data));
for(var i = 0; i < data.data.length; i++) {
// 执行定义方法create_toy,增加li标签
create_toy(data.data[i]);
} }
); function play_anything(content) { //播放音频
// 创建播放对象,拼接路径
player = plus.audio.createPlayer(window.serv_audio + content);
console.log(window.serv_audio + content); //打印路径
// http://192.168.11.86:9527/get_audio/a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3
player.play(); // 播放音频
} document.getElementById("play").addEventListener("tap", function() {
player.play();
}); document.getElementById("pause").addEventListener("tap", function() {
player.pause(); //暂停
}); document.getElementById("resume").addEventListener("tap", function() {
player.resume(); //继续
}); document.getElementById("stop").addEventListener("tap", function() {
player.stop(); // 停止,直接清空player中的对象
}); //发送给玩具
document.getElementById("send2toy").addEventListener("tap", function() {
var index = plus.webview.getWebviewById("HBuilder"); //index.html页面
mui.fire(index, "send_music", { //发送音乐
music_name: music_name, //歌曲名
toy_id: "" // 发给玩具id为12345
})
}); function create_toy(toy_info) { // 创建玩具
// 构造下面的标签
// <li class="mui-table-view-cell">
// <a href="#">Item1</a>
// </li>
var litag = document.createElement("li");
litag.className = "mui-table-view-cell"
var atag = document.createElement("a");
atag.id = toy_info._id; // 玩具id
atag.innerText = toy_info.baby_name;
atag.onclick = function() { // 点击事件
// 获取index页面
var index = plus.webview.getWebviewById("HBuilder")
mui.fire(index, "send_music", { // 使用fire发送数据给index
music_name: music_name, //歌曲名
//玩具id,注意:这里必须是this.id。它表示你点击的是哪个玩具
toy_id: this.id
})
} litag.appendChild(atag);
document.getElementById("toy_list").appendChild(litag);
} })
</script> </html>

index.html页面,就不需要修改了。因为它已经监听了 send_music 事件。

点击 小甜甜

此时,页面的第二个窗口,会自动播放歌曲。

那么点歌功能,就完成了!

三、聊天页面

之前我们写的phone.html,好像没咋用过。将phone.html重命名为 message.html

好友列表,来源于 用户表(users) 的friend_list字段!

修改index.html,将底部选项卡 中的 电话 改为 消息

<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title></title>
<script src="js/mui.js"></script>
<link href="css/mui.min.css" rel="stylesheet" />
</head> <body>
<!--底部选项卡-->
<nav class="mui-bar mui-bar-tab">
<a class="mui-tab-item mui-active" id="index">
<span class="mui-icon mui-icon-home"></span>
<span class="mui-tab-label">首页</span>
</a>
<a class="mui-tab-item" id="message">
<span class="mui-icon mui-icon-chatbubble"></span>
<span class="mui-tab-label">消息</span>
</a>
<a class="mui-tab-item">
<span class="mui-icon mui-icon-email"></span>
<span class="mui-tab-label">邮件</span>
</a>
<a class="mui-tab-item" id="login">
<span class="mui-icon mui-icon-gear"></span>
<span class="mui-tab-label">设置</span>
</a>
</nav>
</body>
<script type="text/javascript" charset="utf-8">
var ws = null; // websocket对象
mui.init({
subpages: [{
url: "main.html",
id: "main.html",
styles: window.styles
}]
});
mui.plusReady(function() {
// console.log(JSON.stringify(plus.webview.currentWebview()))
if(plus.storage.getItem("user")) { // 判断是否登录
console.log('已结登录了!');
//连接websocket连接
ws = new WebSocket("ws://"+window.ws_serv+"/app/"+plus.storage.getItem("user"))
// 客户端接收服务端数据时触发
ws.onmessage = function() {};
}
}); // 消息
document.getElementById("message").addEventListener("tap", function() {
mui.openWindow({
url: "message.html",
id: "message.html",
styles: window.styles,
extras: {
// 传输用户id,给message.html
user_id: plus.storage.getItem("user")
}
})
}); document.getElementById("index").addEventListener("tap", function() {
mui.openWindow({
url: "main.html",
id: "main.html",
styles: window.styles
})
}) document.getElementById("login").addEventListener("tap", function() {
mui.openWindow({
url: "login.html",
id: "login.html",
styles: window.styles
})
}) document.addEventListener("login",function(data){
// fire事件接收消息,使用data.detail
// index是为做显示区分
mui.toast("index"+data.detail.msg)
}); document.addEventListener("send_music", function(data) { //监听send_music事件
var music_name = data.detail.music_name; //获取player.html使用fire发送的music_name值
var toy_id = data.detail.toy_id; //获取发送的玩具id send_str = { //构造数据
music_name:music_name,
toy_id:toy_id
}
// 发送数据给后端,注意要json序列化
ws.send(JSON.stringify(send_str));
}); </script> </html>

底部选项卡,效果如下:

修改 message.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="friend_list"> </ul>
</div>
</body>
<script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
mui.init()
var Sdata = null;
mui.back = function(){}; // 加载HTML5Puls
mui.plusReady(function() {
Sdata = plus.webview.currentWebview();
// post请求
mui.post(
// 好友列表
window.serv + "/friend_list",
{user_id:Sdata.user_id},
function(data){
console.log(JSON.stringify(data));
}
)
}); </script> </html>

进入 flask项目,进入serv目录,新建文件friend.py

from flask import Blueprint, request, jsonify
from setting import MONGO_DB
from setting import RET
from bson import ObjectId fri = Blueprint("fri", __name__) @fri.route("/friend_list", methods=["POST"])
def friend_list(): # 好友列表
user_id = request.form.get("user_id")
# 查询用户id信息
res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})
friend_list = res.get("friend_list") # 获取好友列表 RET["code"] = 0
RET["msg"] = ""
RET["data"] = friend_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
from serv import friend 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.register_blueprint(friend.fri) @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控制台输出:

 {"code":0,"data":[{"friend_avatar":"girl.jpg","friend_chat":"5ba0f1f2e12532418089bf87","friend_id":"5ba0f1f2e12532418089bf88","friend_name":"小可爱","friend_remark":"小甜甜"},{"friend_avatar":"girl.jpg","friend_chat":"5ba21c84e1253229c4acbd11","friend_id":"5ba21c84e1253229c4acbd12","friend_name":"嘻嘻","friend_remark":"小豆芽"}],"msg":""} at message.html:37

已经得到了数据,下面开始渲染页面!

修改 message.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="friend_list"> </ul>
</div>
</body>
<script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
mui.init()
var Sdata = null;
mui.back = function(){}; // 加载HTML5Puls
mui.plusReady(function() {
Sdata = plus.webview.currentWebview();
// post请求
mui.post(
// 好友列表
window.serv + "/friend_list",
{user_id:Sdata.user_id},
function(data){
console.log(JSON.stringify(data));
// 循环好友列表
for (var i = 0; i < data.data.length; i++) {
// 执行自定义方法,渲染页面
create_content(data.data[i]);
}
}
)
}); function create_content(content){
// <li class="mui-table-view-cell mui-media">
// <a href="javascript:;">
// <img class="mui-media-object mui-pull-left" src="../images/shuijiao.jpg">
// <div class="mui-media-body">
// 幸福
// <p class='mui-ellipsis'>能和心爱的人一起睡觉,是件幸福的事情;可是,打呼噜怎么办?</p>
// </div>
// </a>
// </li>
var litag = document.createElement("li");
litag.className = "mui-table-view-cell mui-media";
var atag = document.createElement("a");
atag.id = content.friend_id;
// 点击事件
atag.onclick = function(){
console.log(this.id);
// open_chat(this.id);
} var imgtag = document.createElement("img");
imgtag.className = "mui-media-object mui-pull-left"; imgtag.src = "avatar/" + content.friend_avatar; var divtag = document.createElement("div");
divtag.className = "mui-media-body";
divtag.innerText = content.friend_remark;
var ptag = document.createElement("p");
ptag.className = "mui-ellipsis";
ptag.innerText = content.friend_name; litag.appendChild(atag);
atag.appendChild(imgtag);
atag.appendChild(divtag);
divtag.appendChild(ptag); document.getElementById("friend_list").appendChild(litag);
} </script> </html>

重新访问,效果如下:

点击小甜甜,查看HBuilder控制台输出:

 5ba0f1f2e12532418089bf88 at message.html:63

它会打印出,好友id。那么下面就可以开始聊天了!

新建css文件

chat.css

div.speech {
float: left;
margin: 0, 0;
padding: 6px;
table-layout: fixed;
word-break: break-all;
position: relative;
background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#ffffff), color-stop(0.1, #ececec), color-stop(0.5, #dbdbdb), color-stop(0.9, #dcdcdc), to(#8c8c8c));
border: 1px solid #989898;
border-radius: 8px;
} div.speech:before {
content: '';
position: absolute;
width: 0;
height: 0;
left: 15px;
top: -20px;
border: 10px solid;
border-color: transparent transparent #989898 transparent;
} div.speech:after {
content: '';
position: absolute;
width: 0;
height: 0;
left: 17px;
top: -16px;
border: 8px solid;
border-color: transparent transparent #ffffff transparent;
} div.speech.right {
display: inline-block;
box-shadow: -2px 2px 5px #CCC;
margin-right: 10px;
max-width: 75%;
float: right;
background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#e4ffa7), color-stop(0.1, #bced50), color-stop(0.4, #aed943), color-stop(0.8, #a7d143), to(#99BF40));
} div.speech.right:before {
content: '';
position: absolute;
width: 0;
height: 0;
top: 9px;
bottom: auto;
left: auto;
right: -10px;
border-width: 9px 0 9px 10px;
border-color: transparent #989898;
} div.speech.right:after {
content: '';
position: absolute;
width: 0;
height: 0;
top: 10px;
bottom: auto;
left: auto;
right: -8px;
border-width: 8px 0 8px 9px;
border-color: transparent #bced50;
} div.left {
display: inline-block;
box-shadow: 2px 2px 2px #CCCCCC;
margin-left: 10px;
max-width: 75%;
position: relative;
background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#ffffff), color-stop(0.1, #eae8e8), color-stop(0.4, #E3E3E3), color-stop(0.8, #DFDFDF), to(#D9D9D9));
} div.left:before {
content: '';
position: absolute;
width: 0;
height: 0;
top: 9px;
bottom: auto;
left: -10px;
border-width: 9px 10px 9px 0;
border-color: transparent #989898;
} div.left:after {
content: '';
position: absolute;
width: 0;
height: 0;
top: 10px;
bottom: auto;
left: -8px;
border-width: 8px 9px 8px 0;
border-color: transparent #eae8e8;
} .leftimg {
float: left;
margin-top: 10px;
} .rightimg {
float: right;
margin-top: 10px;
} .leftd {
clear: both;
float: left;
margin-left: 10px;
margin-top: 15px;
} .rightd {
clear: both;
float: right;
margin-top: 15px;
margin-right: 10px;
} .leftd_h {
width: 45px;
height: 35px;
border-radius: 100%;
display: block;
float: left;
overflow: hidden;
} .leftd_h img {
display: block;
width: 100%;
height: auto;
} .rightd_h {
width: 45px;
height: 35px;
border-radius: 100%;
display: block;
float: right;
overflow: hidden;
} .rightd_h img {
display: block;
width: 100%;
height: auto;
} .chat-other {
background-color: red;
margin-top: 10px;
margin-left: 20px;
} .chat-other-span {
background-color: aquamarine;
/*border-radius: 10%;*/
height: 18px;
} .chat-mine {
margin-top: 10px;
margin-right: 20px;
text-align: right;
} .chat-avatar {
border-radius: 100%;
width: 25px;
height: 25px;
}

新建文件chat.html

手势事件

在开发移动端的应用时,会用到很多的手势操作,比如滑动、长按等,为了方便开放者快速集成这些手势,mui内置了常用的手势事件,目前支持的手势事件见如下列表:

参考链接:

http://dev.dcloud.net.cn/mui/event/#gesture

这里, 只用到了 长按里面的 hold和release

修改 chat.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" />
<link rel="stylesheet" type="text/css" href="css/chat.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">与xxx进行对话</h1>
</header>
<div class="mui-content" id="chat_list">
<div class="leftd">
<img src="avatar/girl.jpg" class="leftd_h" />
<div class="speech left">点击播放</div>
</div>
<div class="rightd">
<img src="avatar/girl.jpg" class="rightd_h" />
<div class="speech right">点击播放</div>
</div>
</div>
<nav class="mui-bar mui-bar-tab">
<a class="mui-tab-item mui-active" id="talk">
<span class="mui-icon mui-icon-speech"></span>
<span class="mui-tab-label">按住说话</span>
</a>
</nav>
</body>
<script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
mui.init({
//手势事件配置
gestureConfig: {
tap: true, //默认为true
doubletap: true, //默认为false
longtap: false, //默认为false
swipe: true, //默认为true
drag: true, //默认为true
hold: true, //默认为false,不监听
release: true //默认为false,不监听
}
});
var index = null;
var Sdata=null;
mui.plusReady(function() {
index = plus.webview.getWebviewById("HBuilder");
Sdata = plus.webview.currentWebview();
})
var rec = null; document.getElementById("talk").addEventListener("hold", function() {
mui.toast("按住了");
}) document.getElementById("talk").addEventListener("release", function() {
mui.toast("松开了");
}) function create_chat(who, p) {
// 构建div,一次说话,就是一个div
// <div class="leftd">
// <img src="avatar/girl.jpg" class="leftd_h" />
// <div class="speech left">点击播放</div>
// </div>
// 默认显示在左边
var div1class = "leftd";
var imgclass = "leftd_h";
var div2class = "speech left"; // 左右列表排序效果只是class不一样而已!
// 这里做一个判断,当为self,class改为right
if(who == "self") {
div1class = "rightd";
imgclass = "rightd_h";
div2class = "speech right";
} var div1tag = document.createElement("div");
div1tag.className = div1class;
var imgtag = document.createElement("img");
imgtag.className = imgclass;
imgtag.src = "avatar/girl.jpg"
var div2tag = document.createElement("div");
div2tag.className = div2class;
div2tag.innerText = "点击播放"; div1tag.appendChild(imgtag);
div1tag.appendChild(div2tag); document.getElementById("chat_list").appendChild(div1tag); }
// 生成几个div。一个div就是一次说话
create_chat("self"); // self表示我
create_chat("w"); // 这个可以随便写,表示其他
create_chat("self");
create_chat("");
create_chat(""); </script> </html>

修改 message.html,增加点击事件。点击时,跳转到chat.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="friend_list"> </ul>
</div>
</body>
<script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
mui.init()
var Sdata = null;
mui.back = function(){}; // 加载HTML5Puls
mui.plusReady(function() {
Sdata = plus.webview.currentWebview();
// post请求
mui.post(
// 好友列表
window.serv + "/friend_list",
{user_id:Sdata.user_id},
function(data){
console.log(JSON.stringify(data));
// 循环好友列表
for (var i = 0; i < data.data.length; i++) {
// 执行自定义方法,渲染页面
create_content(data.data[i]);
}
}
)
}); function create_content(content){
// <li class="mui-table-view-cell mui-media">
// <a href="javascript:;">
// <img class="mui-media-object mui-pull-left" src="../images/shuijiao.jpg">
// <div class="mui-media-body">
// 幸福
// <p class='mui-ellipsis'>能和心爱的人一起睡觉,是件幸福的事情;可是,打呼噜怎么办?</p>
// </div>
// </a>
// </li>
var litag = document.createElement("li");
litag.className = "mui-table-view-cell mui-media";
var atag = document.createElement("a");
atag.id = content.friend_id;
// 点击事件
atag.onclick = function(){
console.log(this.id);
open_chat(this.id); //执行自定义方法open_chat
} var imgtag = document.createElement("img");
imgtag.className = "mui-media-object mui-pull-left"; imgtag.src = "avatar/" + content.friend_avatar; var divtag = document.createElement("div");
divtag.className = "mui-media-body";
divtag.innerText = content.friend_remark;
var ptag = document.createElement("p");
ptag.className = "mui-ellipsis";
ptag.innerText = content.friend_name; litag.appendChild(atag);
atag.appendChild(imgtag);
atag.appendChild(divtag);
divtag.appendChild(ptag); document.getElementById("friend_list").appendChild(litag);
} function open_chat(friend_id){ // 打开chat.html
mui.openWindow({
url:"chat.html",
id:"chat.html",
extras:{
// 传参给chat.html
friend_id:friend_id
}
})
} </script> </html>

使用模拟器访问,效果如下:

四、app录音

由于时间关系,详细步骤略...

五、app与服务器端文件传输

由于时间关系,详细步骤略...

六、简单的对话

由于时间关系,详细步骤略...

今日总结:

1.玩具开机提示语
刚刚开机的时候:
1.授权问题(MD5授权码)提示语 : 请联系玩具厂商
2.绑定问题 提示语 : 快给我找一个小主人
3.成功 提示语:欢迎使用 2.为多个玩具发送点播:
mpop 弹出菜单 3.聊天界面:
<div class="leftd">
<img src="avatar/girl.jpg" class="leftd_h" />
<div class="speech left">点击播放</div>
</div>
<div class="rightd">
<img src="avatar/girl.jpg" class="rightd_h" />
<div class="speech right">点击播放</div>
</div> 按住录音:
hold: 按住事件 开始录音(回调函数)
release: 松开事件 结束录音 执行录音中的回调函数 4.app录音:
var rec = plus.audio.getRcorder()
rec.record(
{filename:"_doc/audio/",format:"amr"},
function(success){ success //录音文件保存路径 },
function(error){}
) rec.stop() 5.app与服务器端文件传输(ws传输):
1.app使用dataURL方式打开录音文件 : base64 文件
2.通过某个函数 将 Base64 格式的文件 转为 Blob 用于 websocket传输
3.将Blob对象使用Ws发送至服务端
4.服务端保存文件(amr)
5.将amr 转换为 mp3 使用 ffmpeg -i xxx.amr xxx.mp3 6.简单的对话(app向玩具(web)发起):
app: 1.发起两次 ws.send({to_user:}) 告诉服务端我要发给谁消息
2. ws.send(blob) app与服务器端文件传输 websocket服务:
0.创建两个变量,用于接收to_user 和 blob对象
1.收到用户的JSON字符串,to_user
获取对方的Websocket,用户send
2.收到用户的Blob对象,语音文件
保存成amr文件,转换成mp3
注意保存文件的路径 3.将转换完成的文件发送给 to_user 4.两个变量置空

由于时间关系,详细步骤略...,主要修改了3个文件。

MyApp: chat.html,index.html

banana:  im_serv.py

最终效果,使用APP给 小甜甜 说一段话:

第二个网页,也就是小甜甜的,会自动播放声音

完整代码,请参考github:

https://github.com/987334176/Intelligent_toy/archive/v1.3.zip

未完待续。。。

python 全栈开发,Day129(玩具开机提示语,为多个玩具发送点播,聊天界面,app录音,app与服务器端文件传输,简单的对话)的更多相关文章

  1. python 全栈开发,Day139(websocket原理,flask之请求上下文)

    昨日内容回顾 flask和django对比 flask和django本质是一样的,都是web框架. 但是django自带了一些组件,flask虽然自带的组件比较少,但是它有很多的第三方插件. 那么在什 ...

  2. python 全栈开发之路 day1

    python 全栈开发之路 day1   本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可 ...

  3. Win10构建Python全栈开发环境With WSL

    目录 Win10构建Python全栈开发环境With WSL 启动WSL 总结 对<Dev on Windows with WSL>的补充 Win10构建Python全栈开发环境With ...

  4. python全栈开发中级班全程笔记(第二模块、第四章)(常用模块导入)

    python全栈开发笔记第二模块 第四章 :常用模块(第二部分)     一.os 模块的 详解 1.os.getcwd()    :得到当前工作目录,即当前python解释器所在目录路径 impor ...

  5. Python全栈开发记录_第一篇(循环练习及杂碎的知识点)

    Python全栈开发记录只为记录全栈开发学习过程中一些难和重要的知识点,还有问题及课后题目,以供自己和他人共同查看.(该篇代码行数大约:300行) 知识点1:优先级:not>and 短路原则:a ...

  6. python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)

    昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...

  7. Python全栈开发【面向对象进阶】

    Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...

  8. Python全栈开发【面向对象】

    Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...

  9. Python全栈开发【模块】

    Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...

随机推荐

  1. springcloud报错集合

    springcloud启动报错Connection refused: connect 参考:https://blog.csdn.net/deemo__/article/details/78932401 ...

  2. 一张图看懂JavaScript中数组的迭代方法:forEach、map、filter、reduce、every、some

    好吧,竟然不能单发一张图,不够200字啊不够200字! 在<JavaScript高级程序设计>中,分门别类介绍了非常多数组方法,其中迭代方法里面有6种,这6种方法在实际项目有着非常广泛的作 ...

  3. Linux命令(十)打包压缩、软件安装

  4. 任意两点间的最短路问题(Floyd-Warshall算法)

    #define _CRT_SECURE_NO_WARNINGS /* 7 10 0 1 5 0 2 2 1 2 4 1 3 2 2 3 6 2 4 10 3 5 1 4 5 3 4 6 5 5 6 9 ...

  5. SQL Server 备份还原

    SQL Server支持三种备份方式 完全备份: 差异备份 事务日志备份 一般备份方式为,完全备份/每周,差异备份/每天,事务日志备份/按分钟计,这样可确保备份的高效性和可恢复性. 1. 完全备份 备 ...

  6. android 基础题

    1. Android的四大组件是哪些,它们的作用? (1).Activity:Activity是Android程序与用户交互的窗口,是Android构造块中最基本的一种,它需要为保持各界面的状态,做很 ...

  7. SpringBoot几个重要的事件回调、监听机制

    (1).需要配置在META-INF/Spring.factories 1.ApplicationContextInitializer // // Source code recreated from ...

  8. 【PE结构】PIMAGE_FILE_HEADER中TimeDateStamp的时间戳与标准时间转换

    计算PE文件创建时间,需要对时间进行转换,也就是将时间戳转换成特定的格式,或者特定的格式转换成时间戳. pImageFileHeader->TimeDateStamp的值为1487665851 ...

  9. Mean shift

    转载:http://blog.csdn.net/google19890102/article/details/51030884 然后引入opencv中的pyrMeanShiftFiltering函数: ...

  10. nodejs 使用http模块保存源码

    var xpath=require("xpath"); var fs=require("fs"); var dom = require('xmldom').DO ...