• 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

    未完待续。。。

  • 相关阅读:
    python 字节数组和十六进制字符串互转
    python 字符串转换成字节的三种方式
    python 将16进制转为字节
    python tcp
    Mac下安装与配置Go语言开发环境
    Remastersys -- 将正在使用的Ubuntu14.04 制作成镜像文件
    Python四大主流网络编程框架
    Python之dict(或对象)与json之间的互相转化
    Python中通过csv的writerow输出的内容有多余的空行
    python写入csv文件的几种方法总结
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9674805.html
Copyright © 2020-2023  润新知