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>
View Code

修改 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("联系玩具厂")
View Code

重启 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 = "11712345"
API_KEY = "3v3igzCkVFUDwFByNEE12345"
SECRET_KEY = "jRnwLE7kzC1aRi2FD10OQY3y9Og12345"
SPEECH = {
    "spd": 4,
    'vol': 5,
    "pit": 8,
    "per": 4
}
View Code

修改 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)
View Code

执行 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)
View Code

执行 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)
View Code

执行 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)
View Code

修改 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>
View Code

重启 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=" 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;
                     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:"123456"  // 发给玩具id为12345
                })
            });
            
        })
    </script>

</html>
View Code

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

上面的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=" 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;
                     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: "123456" // 发给玩具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>
View Code

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

点击 小豆芽 是没有效果的!需要增加点击事件。由于它是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=" 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;
                     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: "123456" // 发给玩具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>
View Code

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>
View Code

底部选项卡,效果如下:

修改 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>
View Code

进入 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)
View Code

修改 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)
View Code

重启 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>
View Code

重新访问,效果如下:

 点击小甜甜,查看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;
     0;
    height: 0;
    left: 15px;
    top: -20px;
    border: 10px solid;
    border-color: transparent transparent #989898 transparent;
}

div.speech:after {
    content: '';
    position: absolute;
     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- 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;
     0;
    height: 0;
    top: 9px;
    bottom: auto;
    left: auto;
    right: -10px;
    border- 9px 0 9px 10px;
    border-color: transparent #989898;
}

div.speech.right:after {
    content: '';
    position: absolute;
     0;
    height: 0;
    top: 10px;
    bottom: auto;
    left: auto;
    right: -8px;
    border- 8px 0 8px 9px;
    border-color: transparent #bced50;
}

div.left {
    display: inline-block;
    box-shadow: 2px 2px 2px #CCCCCC;
    margin-left: 10px;
    max- 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;
     0;
    height: 0;
    top: 9px;
    bottom: auto;
    left: -10px;
    border- 9px 10px 9px 0;
    border-color: transparent #989898;
}

div.left:after {
    content: '';
    position: absolute;
     0;
    height: 0;
    top: 10px;
    bottom: auto;
    left: -8px;
    border- 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 {
     45px;
    height: 35px;
    border-radius: 100%;
    display: block;
    float: left;
    overflow: hidden;
}

.leftd_h img {
    display: block;
     100%;
    height: auto;
}

.rightd_h {
     45px;
    height: 35px;
    border-radius: 100%;
    display: block;
    float: right;
    overflow: hidden;
}

.rightd_h img {
    display: block;
     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%;
     25px;
    height: 25px;
}
View Code

新建文件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("2");
        create_chat("2");

        
    </script>

</html>
View Code

修改 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>
View Code

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

四、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.两个变量置空
View Code

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

MyApp: chat.html,index.html

banana:  im_serv.py

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

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

完整代码,请参考github:

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

未完待续。。。

原文地址:https://www.cnblogs.com/xiao987334176/p/9674805.html