python 全栈开发,Day129(玩具开机提示语,为多个玩具发送点播,聊天界面,app录音,app与服务器端文件传输,简单的对话)
一、玩具开机提示语
先下载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与服务器端文件传输,简单的对话)的更多相关文章
- python 全栈开发,Day139(websocket原理,flask之请求上下文)
昨日内容回顾 flask和django对比 flask和django本质是一样的,都是web框架. 但是django自带了一些组件,flask虽然自带的组件比较少,但是它有很多的第三方插件. 那么在什 ...
- python 全栈开发之路 day1
python 全栈开发之路 day1 本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可 ...
- Win10构建Python全栈开发环境With WSL
目录 Win10构建Python全栈开发环境With WSL 启动WSL 总结 对<Dev on Windows with WSL>的补充 Win10构建Python全栈开发环境With ...
- python全栈开发中级班全程笔记(第二模块、第四章)(常用模块导入)
python全栈开发笔记第二模块 第四章 :常用模块(第二部分) 一.os 模块的 详解 1.os.getcwd() :得到当前工作目录,即当前python解释器所在目录路径 impor ...
- Python全栈开发记录_第一篇(循环练习及杂碎的知识点)
Python全栈开发记录只为记录全栈开发学习过程中一些难和重要的知识点,还有问题及课后题目,以供自己和他人共同查看.(该篇代码行数大约:300行) 知识点1:优先级:not>and 短路原则:a ...
- python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)
昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...
- Python全栈开发【面向对象进阶】
Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...
- Python全栈开发【面向对象】
Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...
- Python全栈开发【模块】
Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...
随机推荐
- springcloud报错集合
springcloud启动报错Connection refused: connect 参考:https://blog.csdn.net/deemo__/article/details/78932401 ...
- 一张图看懂JavaScript中数组的迭代方法:forEach、map、filter、reduce、every、some
好吧,竟然不能单发一张图,不够200字啊不够200字! 在<JavaScript高级程序设计>中,分门别类介绍了非常多数组方法,其中迭代方法里面有6种,这6种方法在实际项目有着非常广泛的作 ...
- Linux命令(十)打包压缩、软件安装
- 任意两点间的最短路问题(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 ...
- SQL Server 备份还原
SQL Server支持三种备份方式 完全备份: 差异备份 事务日志备份 一般备份方式为,完全备份/每周,差异备份/每天,事务日志备份/按分钟计,这样可确保备份的高效性和可恢复性. 1. 完全备份 备 ...
- android 基础题
1. Android的四大组件是哪些,它们的作用? (1).Activity:Activity是Android程序与用户交互的窗口,是Android构造块中最基本的一种,它需要为保持各界面的状态,做很 ...
- SpringBoot几个重要的事件回调、监听机制
(1).需要配置在META-INF/Spring.factories 1.ApplicationContextInitializer // // Source code recreated from ...
- 【PE结构】PIMAGE_FILE_HEADER中TimeDateStamp的时间戳与标准时间转换
计算PE文件创建时间,需要对时间进行转换,也就是将时间戳转换成特定的格式,或者特定的格式转换成时间戳. pImageFileHeader->TimeDateStamp的值为1487665851 ...
- Mean shift
转载:http://blog.csdn.net/google19890102/article/details/51030884 然后引入opencv中的pyrMeanShiftFiltering函数: ...
- nodejs 使用http模块保存源码
var xpath=require("xpath"); var fs=require("fs"); var dom = require('xmldom').DO ...