python 全栈开发,Day131(向app推送消息,玩具端消息推送)

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

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

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

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

请参考链接:

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

 

一、向app推送消息

redis安装

Redis项目并没有正式支持Windows。然而,微软OpenTeaGeo集团开发并维护了以WIN64为目标的Windows端口。链接如下:

https://github.com/MicrosoftArchive/redis/releases

 

目前最新版本是3.2

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

完整下载链接如下:

https://github.com/MicrosoftArchive/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.msi

 

开始安装

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 注意:要勾选添加到系统环境变量

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 默认端口是6379

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

设置最大内存,这里不设置。表示不限制内存大小!

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

安装完成后,打开cmd窗口,运行命令

d:

cd D:\Program Files\Redis

redis-server.exe redis.windows.conf

redis-cli

效果如下:

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

使用Python操作redis,需要安装模块redis

pip install redis

接下来的操作,会将消息数量,存在redis中!

 

显示消息数量

如果有消息来了,需要在底部选项卡中的消息按钮,显示角标。比如这样:

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

还有 好友列表,也要显示角标。谁发送了几条消息,比如这样:

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

消息按钮显示未读消息

进入flask项目,修改setting.py,增加redis配置

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
import pymongo
import os
import redis

# 数据库配置
client = pymongo.MongoClient(host="127.0.0.1", port=27017)
MONGO_DB = client["bananabase"]

REDIS_DB = redis.Redis(host="127.0.0.1",port=6379)

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

# 文件目录


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")  # 二维码
CHAT_FILE = os.path.join(os.path.dirname(__file__), "chat")  # 聊天

# 百度AI配置
APP_ID = "117912345"
API_KEY = "3v3igzCkVFUDwFByNEE12345"
SECRET_KEY = "jRnwLE7kzC1aRi2FD10OQY3y9O12345"
SPEECH = {
    "spd": 4,
    'vol': 5,
    "pit": 8,
    "per": 4
}
View Code

 

进入utils文件夹,创建文件 chat_redis.py

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from setting import REDIS_DB
import json


def save_msg(小甜甜,xiao):
    """

    key: xiao
    {
        小甜甜:5,
        小豆芽:4
    }
    :return:

    """
    res = json.loads(REDIS_DB.get(xiao))
    res["小甜甜"] = 1
    if res:
        pass

    REDIS_DB.set(xiao,json.dumps(res))
View Code

 

看下面的示例图:

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

修改 chat_redis.py

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from setting import REDIS_DB
import json


def save_msg(sender, to_user):  # 保存消息
    # 1.查询一下xiao的Redis是否有数据
    user_msg_redis = REDIS_DB.get(to_user)
    if user_msg_redis:
        # 2.将xiao的数据反序列化成字典 { sender : n }
        user_msg_dict = json.loads(user_msg_redis)
        # 3.判断有没有 sender 的用户发来的消息数量
        if user_msg_dict.get(sender):
            # 数量加1
            user_msg_dict[sender] += 1
        else:
            # 第一次,初始值为1
            user_msg_dict[sender] = 1
    # 4.如果xiao是刚建立好的用户,他是没有消息的,字典是空
    else:
        user_msg_dict = {sender: 1}

    # 5.序列化用户消息字典user_msg_dict
    user_msg_redis = json.dumps(user_msg_dict)
    # 6.存回Redis
    REDIS_DB.set(to_user, user_msg_redis)

def get_msg_list(user):  # 获取消息
    user_msg_redis = REDIS_DB.get(user)
    if user_msg_redis:
        user_msg_dict = json.loads(user_msg_redis)
        # 统计数量
        user_msg_dict["count"] = sum(user_msg_dict.values())
    else:
        user_msg_dict = {"count":0}

    return user_msg_dict

def get_user_msg_one(sender, to_user):  # 获取一条消息
    user_msg_redis = REDIS_DB.get(to_user)
    if user_msg_redis:
        user_msg_dict = json.loads(user_msg_redis)
        if user_msg_dict.get(sender):
            return user_msg_dict.get(sender)
View Code

 

修改 im_serv.py

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from flask import Flask, request
from geventwebsocket.websocket import WebSocket
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
import json, os
from uuid import uuid4
from setting import AUDIO_FILE,CHAT_FILE
from serv import content
from utils import baidu_ai
from utils import chat_redis
import setting
from bson import ObjectId
import time

app = Flask(__name__)

user_socket_dict = {}  # 空字典,用来存放用户名和发送消息


@app.route("/toy/<tid>")
def toy(tid):  # 玩具连接
    # 获取请求的WebSocket对象
    user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
    if user_socket:
        # 设置键值对
        user_socket_dict[tid] = user_socket
        print(user_socket_dict)
        # {'123456': <geventwebsocket.websocket.WebSocket object at 0x00000176ABD92E18>}

    file_name = ""
    to_user = ""
    # 循环,接收消息
    while True:
        msg = user_socket.receive()
        if type(msg) == bytearray:
            file_name = f"{uuid4()}.wav"
            file_path = os.path.join(CHAT_FILE, file_name)
            with open(file_path, "wb") as f:
                f.write(msg)
        else:
            msg_dict = json.loads(msg)
            to_user = msg_dict.get("to_user")
            msg_type = msg_dict.get("msg_type")

        if to_user and file_name:
            other_user_socket = user_socket_dict.get(to_user)
            if msg_type == "ai":
                q = baidu_ai.audio2text(file_path)
                print(q)
                ret = baidu_ai.my_nlp(q, tid)
                other_user_socket.send(json.dumps(ret))
            else:
                send_str = {
                    "code": 0,
                    "from_user": tid,
                    "msg_type": "chat",
                    "data": file_name
                }

                if other_user_socket:  # 当websocket连接存在时
                    chat_redis.save_msg(tid, to_user)  # 保存消息到redis
                    # 发送数据
                    other_user_socket.send(json.dumps(send_str))
                else:
                    # 离线消息
                    chat_redis.save_msg(tid, to_user)

                # 保存聊天记录到MongoDB
                _add_chat(tid, to_user, send_str.get("data"))

            to_user = ""
            file_name = ""


@app.route("/app/<uid>")
def user_app(uid):  # 手机app连接
    user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
    if user_socket:
        user_socket_dict[uid] = user_socket
        # { uid : websocket}
        print(user_socket_dict)

    file_name = ""
    to_user = ""

    while True:  # 手机听歌 把歌曲发送给 玩具 1.将文件直接发送给玩具 2.将当前听的歌曲名称或ID发送到玩具
        msg = user_socket.receive()
        if type(msg) == bytearray:  # 判断类型为bytearray
            file_name = f"{uuid4()}.amr"  # 文件后缀为amr,安卓和ios通用
            file_path = os.path.join(CHAT_FILE, file_name)  # 存放在chat目录
            print(msg)
            with open(file_path, "wb") as f:
                f.write(msg)  # 写入文件

            # 将amr转换为mp3,因为html中的audio不支持amr
            os.system(f"ffmpeg -i {file_path} {file_path}.mp3")

        else:
            msg_dict = json.loads(msg)
            to_user = msg_dict.get("to_user")  # 获取目标用户

            if msg_dict.get("msg_type") == "music":
                other_user_socket = user_socket_dict.get(to_user)

                send_str = {
                    "code": 0,
                    "from_user": uid,
                    "msg_type": "music",
                    "data": msg_dict.get("data")
                }
                other_user_socket.send(json.dumps(send_str))

            # res = content._content_one(content_id)
        if file_name and to_user:  # 如果文件名和发送用户同上存在时
            # 查询玩具信息
            res = setting.MONGO_DB.toys.find_one({"_id": ObjectId(to_user)})
            # 获取friend_remark
            fri = [i.get("friend_remark") for i in res.get("friend_list") if i.get("friend_id") == uid][0]
            msg_file_name = baidu_ai.text2audio(f"你有来自{fri}的消息")

            # 获取websocket对象
            other_user_socket = user_socket_dict.get(to_user)
            # 构造数据
            send_str = {
                "code": 0,
                "from_user": uid,
                "msg_type": "chat", # 聊天类型
                # 后缀必须是mp3的
                "data": msg_file_name
            }
            # 发送数据给前端页面
            other_user_socket.send(json.dumps(send_str))
            # 添加聊天记录到数据库
            _add_chat(uid, to_user, f"{file_name}.mp3")
            # 最后一定要清空这2个变量,否则造成混乱
            file_name = ""
            to_user = ""

def _add_chat(sender, to_user, msg):  # 添加聊天记录到数据库
    chat_window = setting.MONGO_DB.chat.find_one({"user_list": {"$all": [sender, to_user]}})
    if not chat_window.get("chat_list"):
        chat_window["chat_list"] = [{
            "sender": sender,
            "msg": msg,
            "updated_at": time.time(),
        }]
        res = setting.MONGO_DB.chat.update_one({"_id": ObjectId(chat_window.get("_id"))}, {"$set": chat_window})
    else:
        chat = {
            "sender": sender,
            "msg": msg,
            "updated_at": time.time(),
        }
        res = setting.MONGO_DB.chat.update_one({"_id": ObjectId(chat_window.get("_id"))}, {"$push": {"chat_list": chat}})

    return res

if __name__ == '__main__':
    # 创建一个WebSocket服务器
    http_serv = WSGIServer(("0.0.0.0", 9528), app, handler_class=WebSocketHandler)
    # 开始监听HTTP请求
    http_serv.serve_forever()


'''
{
    "code": 0,
    "from_user": uid,  # APP用户id
    "data": music_name  # 歌曲名
}
'''
View Code

重启  im_serv.py

 

打开网页,让 小甜甜 开机

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

点击 开始废话,使用麦克风说: 给小鱼 发消息。再点击发送语音!

此时,录制消息按钮后面,会出现 对方id

注意:小鱼 表示玩具对主人(xiao)的称呼

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

再点击 录制消息,说: hello。最后点击发送语音消息

 

进入redis,查看消息,将网页中的 录制消息按钮后面的id复制过来

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

查看用户id的数据,可以发现数量为1

127.0.0.1:6379> get 5b9bb768e1253281608e96eb
"{\"5ba0f1f2e12532418089bf88\": 1}"
127.0.0.1:6379>

那么redis中的数据有了,就可以在APP中渲染了

 

进入HBuilder项目MyApp,修改 index.html,增加角标

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
<!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-chat">
                    <span class="mui-badge mui-badge-red" id="msg_count">0</span>
                </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"))
                
                // 发送post请求
                console.log(window.serv + "/get_msg_list");
                mui.post(
                    // 访问消息列表
                    window.serv + "/get_msg_list", {
                        user_id: plus.storage.getItem("user")
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        msg_data = data.data;
                        // 修改消息选项卡的角标数字
                        document.getElementById("msg_count").innerText = msg_data.count;
                    }
                );
                
                // 客户端接收服务端数据时触发
                ws.onmessage = function() {};
            }
            // 自动重连
            ws.onclose = function() {
                window.location.reload();
            }
        });

        // 消息
        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() {
            // 自动登录,判断storage中的user存在,就跳转到user_info,否则跳转login
            if(plus.storage.getItem("user")) {
                mui.openWindow({
                    url: "user_info.html",
                    id: "user_info.html",
                    styles: window.styles,
                    extras: {
                        user_id: plus.storage.getItem("user")
                    }
                })
            } else {
                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 = { //构造数据
                data: music_name,
                to_user: toy_id, // 目标用户,这里统一格式
                msg_type: "music", // 类型为音乐
            }
            // 发送数据给后端,注意要json序列化
            ws.send(JSON.stringify(send_str));
        });

        document.addEventListener("send_msg", function(data) { //发送消息
            var filename = data.detail.filename
            var to_user = data.detail.to_user
            send_str = {
                to_user: to_user
            }
            ws.send(JSON.stringify(send_str))
            plus.io.resolveLocalFileSystemURL(filename, function(entry) {
                // 可通过entry对象操作test.html文件 
                entry.file(function(file) {
                    // FileReader文件系统中的读取文件对象,用于获取文件的内容
                    var fileReader = new plus.io.FileReader();

                    //                        alert("getFile:" + JSON.stringify(file));
                    // readAsDataURL: 以URL编码格式读取文件数据内容
                    fileReader.readAsDataURL(file, 'utf-8');
                    // onloadend: 文件读取操作完成时的回调函数
                    fileReader.onloadend = function(evt) {
                        console.log(evt.target.result);
                        var b = dataURLtoBlob(evt.target.result);
                        ws.send(b); // 发送blob数据

                    }
                    //                        alert(file.size + '--' + file.name)
                });
            });

        })

        function dataURLtoBlob(dataurl) { // 数据转换为Blob
            // 逻辑很复杂,这里不解释了。直接用就可以了!
            var arr = dataurl.split(','),
                mime = arr[0].match(/:(.*?);/)[1],
                bstr = atob(arr[1]),
                n = bstr.length,
                u8arr = new Uint8Array(n);
            while(n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            var a = new Blob([u8arr], {
                type: mime
            });
            return a
        }
    </script>

</html>
View Code

 

进入 flask项目,修改 serv-->chat.py

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from flask import Blueprint, request, jsonify
from setting import MONGO_DB
from setting import RET
from bson import ObjectId
from utils import chat_redis

cht = Blueprint("cht", __name__)


@cht.route("/chat_list", methods=["POST"])
def chat_list():  # 聊天记录列表
    user_id = request.form.get("user_id")
    friend_id = request.form.get("friend_id")
    print(friend_id)

    chat_window = MONGO_DB.chat.find_one({"user_list": {"$all": [user_id, friend_id]}})
    fri = MONGO_DB.toys.find_one({"_id": ObjectId(friend_id)})
    baby_name = fri.get("baby_name")
    cl = chat_window.get("chat_list")

    RET["code"] = 0
    RET["msg"] = baby_name
    RET["data"] = cl

    return jsonify(RET)


@cht.route("/get_msg", methods=["POST"])
def get_msg():  # 获取聊天语言文件
    user_id = request.form.get("user_id")
    sender = request.form.get("sender")
    chat_window = MONGO_DB.chat.find_one({"user_list": {"$all": [user_id, sender]}})
    new_msg = chat_window.get("chat_list")[-1]

    RET["code"] = 0
    RET["msg"] = ""
    RET["data"] = new_msg.get("msg")

    return jsonify(RET)

@cht.route("/get_msg_list", methods=["POST"])
def get_msg_list():
    user_id = request.form.get("user_id")
    user_msg_dict = chat_redis.get_msg_list(user_id)

    RET["code"] = 0
    RET["msg"] = ""
    RET["data"] = user_msg_dict

    return jsonify(RET)
View Code

重启 manager.py

 

打开模拟器,关闭里面的HBuilder进程,重新开启,效果如下:

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

效果就完成了!

 

聊天窗口显示未读消息

再来做 聊天窗口,显示角标。上面演示时,小甜甜 给 小鱼(主人) 发送了一条消息。

那么下图中的紫色框后面,应该显示数字1

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

那么如何实现呢?答案很简单,使用mui.openWindows打开message.html页面时,给它传一个参数msg_data。

参数大概是这个样子

"data":{"5ba0f1f2e12532418089bf88":1,"count":1}

5ba0f1f2e12532418089bf88 是 小甜甜 的_id。在toys表中可以查询!

 

修改 index.html

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
<!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-chat">
                    <span class="mui-badge mui-badge-red" id="msg_count">0</span>
                </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对象
        var msg_data = null;  // 消息数据
        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"))
                
                // 发送post请求
                console.log(window.serv + "/get_msg_list");
                mui.post(
                    // 访问消息列表
                    window.serv + "/get_msg_list", {
                        user_id: plus.storage.getItem("user")
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        //  {"code":0,"data":{"5ba0f1f2e12532418089bf88":1,"count":1},"msg":""}
                        msg_data = data.data;
                        // 修改消息选项卡的角标数字
                        document.getElementById("msg_count").innerText = msg_data.count;
                    }
                );
                
                // 客户端接收服务端数据时触发
                ws.onmessage = function() {};
            }
            // 自动重连
            ws.onclose = function() {
                window.location.reload();
            }
        });

        // 消息
        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"),
                    msg_data: msg_data,
                    //  "data":{"5ba0f1f2e12532418089bf88":1,"count":1}
                }
            })
        });

        document.getElementById("index").addEventListener("tap", function() {
            mui.openWindow({
                url: "main.html",
                id: "main.html",
                styles: window.styles
            })
        })

        document.getElementById("login").addEventListener("tap", function() {
            // 自动登录,判断storage中的user存在,就跳转到user_info,否则跳转login
            if(plus.storage.getItem("user")) {
                mui.openWindow({
                    url: "user_info.html",
                    id: "user_info.html",
                    styles: window.styles,
                    extras: {
                        user_id: plus.storage.getItem("user")
                    }
                })
            } else {
                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 = { //构造数据
                data: music_name,
                to_user: toy_id, // 目标用户,这里统一格式
                msg_type: "music", // 类型为音乐
            }
            // 发送数据给后端,注意要json序列化
            ws.send(JSON.stringify(send_str));
        });

        document.addEventListener("send_msg", function(data) { //发送消息
            var filename = data.detail.filename
            var to_user = data.detail.to_user
            send_str = {
                to_user: to_user
            }
            ws.send(JSON.stringify(send_str))
            plus.io.resolveLocalFileSystemURL(filename, function(entry) {
                // 可通过entry对象操作test.html文件 
                entry.file(function(file) {
                    // FileReader文件系统中的读取文件对象,用于获取文件的内容
                    var fileReader = new plus.io.FileReader();

                    //                        alert("getFile:" + JSON.stringify(file));
                    // readAsDataURL: 以URL编码格式读取文件数据内容
                    fileReader.readAsDataURL(file, 'utf-8');
                    // onloadend: 文件读取操作完成时的回调函数
                    fileReader.onloadend = function(evt) {
                        console.log(evt.target.result);
                        var b = dataURLtoBlob(evt.target.result);
                        ws.send(b); // 发送blob数据

                    }
                    //                        alert(file.size + '--' + file.name)
                });
            });

        })

        function dataURLtoBlob(dataurl) { // 数据转换为Blob
            // 逻辑很复杂,这里不解释了。直接用就可以了!
            var arr = dataurl.split(','),
                mime = arr[0].match(/:(.*?);/)[1],
                bstr = atob(arr[1]),
                n = bstr.length,
                u8arr = new Uint8Array(n);
            while(n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            var a = new Blob([u8arr], {
                type: mime
            });
            return a
        }
    </script>

</html>
View Code

 

修改 message.html,渲染页面。create_content多加一个参数

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
<!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],Sdata.msg_data);
                    }
                }
            )
        });
        
        function create_content(content,msg_data){    
//            <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 spantag = document.createElement("span");
            spantag.className = "mui-badge mui-badge-red";
            // content是一个字典,要获取friend_id。不能使用get,只能使用.
            // 如果获取不到,值为undefine
            spantag.innerText = msg_data[content.friend_id]
            
            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);
             atag.appendChild(spantag);
             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

 

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

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 发现了 undefined,这个不应该出现角标。这个是一个已知的bug,有兴趣的人,可以修改一下。

提示:使用css中的display:none

 

角标重置

点击 小甜甜,再返回页面时,这里的角标应该重置为0。并且不显示才对。

前端操作

修改 message.html,触发点击事件时,角标重置为0

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
<!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],Sdata.msg_data);
                    }
                }
            )
        });
        
        function create_content(content,msg_data){    
//            <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 spantag = document.createElement("span");
            spantag.className = "mui-badge mui-badge-red";
            // content是一个字典,要获取friend_id。不能使用get,只能使用.
            // 如果获取不到,值为undefine
            spantag.innerText = msg_data[content.friend_id]
            
            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);
                spantag.innerText = 0;  // 重置为0
                //执行自定义方法open_chat
                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);
             atag.appendChild(spantag);
             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

 

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

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

可以发现,聊天列表返回时,已经重置为0了。但是底部现象卡还没有变动!莫急,下面来处理它。

怎么实现呢?由于index.html页面是母模,它只负责显示底部选项卡。

在chat.html页面给index.html,执行一个fire(开火)事件就可以了!但是:一个页面,只能fire一次。

由于chat.html已经存在了一个fire事件。所以只能在message.html做fire

 

修改 message.html,增加fire

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
<!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],Sdata.msg_data);
                    }
                }
            )
        });
        
        function create_content(content,msg_data){    
//            <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 spantag = document.createElement("span");
            spantag.className = "mui-badge mui-badge-red";
            // content是一个字典,要获取friend_id。不能使用get,只能使用.
            // 如果获取不到,值为undefine
            spantag.innerText = msg_data[content.friend_id]
            
            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
                open_chat(this.id,spantag.innerText);
                spantag.innerText = 0;  // 重置为0
                
                
            }

            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);
             atag.appendChild(spantag);
             divtag.appendChild(ptag);
             
             document.getElementById("friend_list").appendChild(litag);
        }
        
        function open_chat(friend_id,cut_count){  // 打开chat.html
            // 获取index.html
            var index = plus.webview.getWebviewById("HBuilder")
            // 执行fire
            mui.fire(index,"cut_msg_count",{cut:cut_count})
            mui.openWindow({
                url:"chat.html",
                id:"chat.html",
                extras:{
                    // 传参给chat.html
                    friend_id:friend_id
                }
            })
        }

    </script>

</html>
View Code

 

修改 index.html,监听 cut_msg_count事件

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
<!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-chat">
                    <span class="mui-badge mui-badge-red" id="msg_count">0</span>
                </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对象
        var msg_data = null;  // 消息数据
        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"))
                
                // 发送post请求
                console.log(window.serv + "/get_msg_list");
                mui.post(
                    // 访问消息列表
                    window.serv + "/get_msg_list", {
                        user_id: plus.storage.getItem("user")
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        //  {"code":0,"data":{"5ba0f1f2e12532418089bf88":1,"count":1},"msg":""}
                        msg_data = data.data;
                        // 修改消息选项卡的角标数字
                        document.getElementById("msg_count").innerText = msg_data.count;
                    }
                );
                
                // 客户端接收服务端数据时触发
                ws.onmessage = function() {};
            }
            // 自动重连
            ws.onclose = function() {
                window.location.reload();
            }
        });

        // 消息
        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"),
                    msg_data: msg_data,
                    //  "data":{"5ba0f1f2e12532418089bf88":1,"count":1}
                }
            })
        });

        document.getElementById("index").addEventListener("tap", function() {
            mui.openWindow({
                url: "main.html",
                id: "main.html",
                styles: window.styles
            })
        })

        document.getElementById("login").addEventListener("tap", function() {
            // 自动登录,判断storage中的user存在,就跳转到user_info,否则跳转login
            if(plus.storage.getItem("user")) {
                mui.openWindow({
                    url: "user_info.html",
                    id: "user_info.html",
                    styles: window.styles,
                    extras: {
                        user_id: plus.storage.getItem("user")
                    }
                })
            } else {
                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 = { //构造数据
                data: music_name,
                to_user: toy_id, // 目标用户,这里统一格式
                msg_type: "music", // 类型为音乐
            }
            // 发送数据给后端,注意要json序列化
            ws.send(JSON.stringify(send_str));
        });

        document.addEventListener("send_msg", function(data) { //发送消息
            var filename = data.detail.filename
            var to_user = data.detail.to_user
            send_str = {
                to_user: to_user
            }
            ws.send(JSON.stringify(send_str))
            plus.io.resolveLocalFileSystemURL(filename, function(entry) {
                // 可通过entry对象操作test.html文件 
                entry.file(function(file) {
                    // FileReader文件系统中的读取文件对象,用于获取文件的内容
                    var fileReader = new plus.io.FileReader();

                    //                        alert("getFile:" + JSON.stringify(file));
                    // readAsDataURL: 以URL编码格式读取文件数据内容
                    fileReader.readAsDataURL(file, 'utf-8');
                    // onloadend: 文件读取操作完成时的回调函数
                    fileReader.onloadend = function(evt) {
                        console.log(evt.target.result);
                        var b = dataURLtoBlob(evt.target.result);
                        ws.send(b); // 发送blob数据

                    }
                    //                        alert(file.size + '--' + file.name)
                });
            });

        });
        
        // 监听cut_msg_count事件,由message.html向index.html执行fire
        document.addEventListener("cut_msg_count", function(data) {
            var msg_count = document.getElementById("msg_count");
            var cut = parseInt(data.detail.cut);  // parseInt表示强制转换
            var count = parseInt(msg_count.innerText);  // 默认获取innerText是字符串,需要强制转换
            msg_count.innerText = count - cut;  // 总数 减去 点击聊天会话的数量,比如小甜甜的
        });

        function dataURLtoBlob(dataurl) { // 数据转换为Blob
            // 逻辑很复杂,这里不解释了。直接用就可以了!
            var arr = dataurl.split(','),
                mime = arr[0].match(/:(.*?);/)[1],
                bstr = atob(arr[1]),
                n = bstr.length,
                u8arr = new Uint8Array(n);
            while(n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            var a = new Blob([u8arr], {
                type: mime
            });
            return a
        }
    </script>

</html>
View Code

 

 效果如下:

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

可以发现,底部选项卡,也变成0了

 

 

后端操作

那是因为后端redis的数据没有更改。

 

进入flask项目,修改 utils-->chat_redis.py

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from setting import REDIS_DB
import json


def save_msg(sender, to_user):  # 保存消息
    # 1.查询一下xiao的Redis是否有数据
    user_msg_redis = REDIS_DB.get(to_user)
    if user_msg_redis:
        # 2.将xiao的数据反序列化成字典 { sender : n }
        user_msg_dict = json.loads(user_msg_redis)
        # 3.判断有没有 sender 的用户发来的消息数量
        if user_msg_dict.get(sender):
            # 数量加1
            user_msg_dict[sender] += 1
        else:
            # 第一次,初始值为1
            user_msg_dict[sender] = 1
    # 4.如果xiao是刚建立好的用户,他是没有消息的,字典是空
    else:
        user_msg_dict = {sender: 1}

    # 5.序列化用户消息字典user_msg_dict
    user_msg_redis = json.dumps(user_msg_dict)
    # 6.存回Redis
    REDIS_DB.set(to_user, user_msg_redis)

def get_msg_list(user):  # 获取消息
    user_msg_redis = REDIS_DB.get(user)
    if user_msg_redis:
        user_msg_dict = json.loads(user_msg_redis)
        # 统计数量
        user_msg_dict["count"] = sum(user_msg_dict.values())
    else:
        user_msg_dict = {"count":0}

    return user_msg_dict

def get_user_msg_one(sender, to_user):  # 获取用户一个好友消息
    user_msg_redis = REDIS_DB.get(to_user)
    if user_msg_redis:
        user_msg_dict = json.loads(user_msg_redis)
        if user_msg_dict.get(sender):
            # return user_msg_dict.get(sender)
            user_msg_dict[sender] = 0

    else:
        user_msg_dict = {sender:0}

    user_msg_redis = json.dumps(user_msg_dict)
    REDIS_DB.set(to_user,user_msg_redis)  # 修改redis
View Code

 

修改 serv-->chat.py,增加 chat_redis.get_user_msg_one

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from flask import Blueprint, request, jsonify
from setting import MONGO_DB
from setting import RET
from bson import ObjectId
from utils import chat_redis

cht = Blueprint("cht", __name__)


@cht.route("/chat_list", methods=["POST"])
def chat_list():  # 聊天记录列表
    user_id = request.form.get("user_id")
    friend_id = request.form.get("friend_id")
    print(friend_id)

    chat_window = MONGO_DB.chat.find_one({"user_list": {"$all": [user_id, friend_id]}})
    fri = MONGO_DB.toys.find_one({"_id": ObjectId(friend_id)})
    baby_name = fri.get("baby_name")
    cl = chat_window.get("chat_list")

    RET["code"] = 0
    RET["msg"] = baby_name
    RET["data"] = cl

    # 获取用户单个好友记录,修改redis的值
    chat_redis.get_user_msg_one(friend_id,user_id)

    return jsonify(RET)


@cht.route("/get_msg", methods=["POST"])
def get_msg():  # 获取聊天语言文件
    user_id = request.form.get("user_id")
    sender = request.form.get("sender")
    chat_window = MONGO_DB.chat.find_one({"user_list": {"$all": [user_id, sender]}})
    new_msg = chat_window.get("chat_list")[-1]

    RET["code"] = 0
    RET["msg"] = ""
    RET["data"] = new_msg.get("msg")

    return jsonify(RET)

@cht.route("/get_msg_list", methods=["POST"])
def get_msg_list():
    user_id = request.form.get("user_id")
    user_msg_dict = chat_redis.get_msg_list(user_id)

    RET["code"] = 0
    RET["msg"] = ""
    RET["data"] = user_msg_dict

    return jsonify(RET)
View Code

 

打开夜神模拟器,重启 里面的HBuilder APP。再次点击,查看redis

127.0.0.1:6379> get 5b9bb768e1253281608e96eb
"{\"5ba0f1f2e12532418089bf88\": 0}"

发现已经更新为0了

 

消息增加

但是发消息,可能不止一条。如果有消息,角标的数字应该自动加。

进入 HBuilder项目MyApp,修改index.html

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
<!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-chat">
                    <span class="mui-badge mui-badge-red" id="msg_count">0</span>
                </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对象
        var msg_data = null;  // 消息数据
        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"))
                
                // 发送post请求
                console.log(window.serv + "/get_msg_list");
                mui.post(
                    // 访问消息列表
                    window.serv + "/get_msg_list", {
                        user_id: plus.storage.getItem("user")
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        //  {"code":0,"data":{"5ba0f1f2e12532418089bf88":1,"count":1},"msg":""}
                        msg_data = data.data;
                        // 修改消息选项卡的角标数字
                        document.getElementById("msg_count").innerText = msg_data.count;
                    }
                );
                
                // 客户端接收服务端数据时触发
                ws.onmessage = function(data) {
                    console.log(data.data);
                    var msg = JSON.parse(data.data);
                    var chat = plus.webview.getWebviewById("chat.html");
                    mui.fire(chat, "new_msg", {  // 向chat.html传值
                        data: msg
                    });
                    var msg_count = document.getElementById("msg_count");
                    // 当前页面加1
                    msg_count.innerText = parseInt(msg_count.innerText) + 1;
                    // 加1,用于message.html显示
                    msg_data[msg.from_user]++;
                };
            }
            // 自动重连
            ws.onclose = function() {
                window.location.reload();
            }
        });

        // 消息
        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"),
                    msg_data: msg_data,
                    //  "data":{"5ba0f1f2e12532418089bf88":1,"count":1}
                }
            })
        });

        document.getElementById("index").addEventListener("tap", function() {
            mui.openWindow({
                url: "main.html",
                id: "main.html",
                styles: window.styles
            })
        })

        document.getElementById("login").addEventListener("tap", function() {
            // 自动登录,判断storage中的user存在,就跳转到user_info,否则跳转login
            if(plus.storage.getItem("user")) {
                mui.openWindow({
                    url: "user_info.html",
                    id: "user_info.html",
                    styles: window.styles,
                    extras: {
                        user_id: plus.storage.getItem("user")
                    }
                })
            } else {
                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 = { //构造数据
                data: music_name,
                to_user: toy_id, // 目标用户,这里统一格式
                msg_type: "music", // 类型为音乐
            }
            // 发送数据给后端,注意要json序列化
            ws.send(JSON.stringify(send_str));
        });

        document.addEventListener("send_msg", function(data) { //发送消息
            var filename = data.detail.filename
            var to_user = data.detail.to_user
            send_str = {
                to_user: to_user
            }
            ws.send(JSON.stringify(send_str))
            plus.io.resolveLocalFileSystemURL(filename, function(entry) {
                // 可通过entry对象操作test.html文件 
                entry.file(function(file) {
                    // FileReader文件系统中的读取文件对象,用于获取文件的内容
                    var fileReader = new plus.io.FileReader();

                    //                        alert("getFile:" + JSON.stringify(file));
                    // readAsDataURL: 以URL编码格式读取文件数据内容
                    fileReader.readAsDataURL(file, 'utf-8');
                    // onloadend: 文件读取操作完成时的回调函数
                    fileReader.onloadend = function(evt) {
                        console.log(evt.target.result);
                        var b = dataURLtoBlob(evt.target.result);
                        ws.send(b); // 发送blob数据

                    }
                    //                        alert(file.size + '--' + file.name)
                });
            });

        });
        
        // 监听cut_msg_count事件,由message.html向index.html执行fire
        document.addEventListener("cut_msg_count", function(data) {
            var msg_count = document.getElementById("msg_count");
            var cut = parseInt(data.detail.cut);  // parseInt表示强制转换
            var count = parseInt(msg_count.innerText);  // 默认获取innerText是字符串,需要强制转换
            msg_count.innerText = count - cut;  // 总数 减去 点击聊天会话的数量,比如小甜甜的
        });

        function dataURLtoBlob(dataurl) { // 数据转换为Blob
            // 逻辑很复杂,这里不解释了。直接用就可以了!
            var arr = dataurl.split(','),
                mime = arr[0].match(/:(.*?);/)[1],
                bstr = atob(arr[1]),
                n = bstr.length,
                u8arr = new Uint8Array(n);
            while(n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            var a = new Blob([u8arr], {
                type: mime
            });
            return a
        }
    </script>

</html>
View Code

 

打开网页,发送消息

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

发送2条消息

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

这里会实时变化

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 这里还是0,是因为这个页面的plusReady只会加载一次。这个是一个小bug

 python 全栈开发,Day131(向app推送消息,玩具端消息推送)

如果关闭进程,再次开启,就会有了!

 

进入 flask后端,修改im_serv.py

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from flask import Flask, request
from geventwebsocket.websocket import WebSocket
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
import json, os
from uuid import uuid4
from setting import AUDIO_FILE,CHAT_FILE
from serv import content
from utils import baidu_ai
from utils import chat_redis
import setting
from bson import ObjectId
import time

app = Flask(__name__)

user_socket_dict = {}  # 空字典,用来存放用户名和发送消息


@app.route("/toy/<tid>")
def toy(tid):  # 玩具连接
    # 获取请求的WebSocket对象
    user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
    if user_socket:
        # 设置键值对
        user_socket_dict[tid] = user_socket
        print(user_socket_dict)
        # {'123456': <geventwebsocket.websocket.WebSocket object at 0x00000176ABD92E18>}

    file_name = ""
    to_user = ""
    # 循环,接收消息
    while True:
        msg = user_socket.receive()
        if type(msg) == bytearray:
            file_name = f"{uuid4()}.wav"
            file_path = os.path.join(CHAT_FILE, file_name)
            with open(file_path, "wb") as f:
                f.write(msg)
        else:
            msg_dict = json.loads(msg)
            to_user = msg_dict.get("to_user")
            msg_type = msg_dict.get("msg_type")

        if to_user and file_name:
            other_user_socket = user_socket_dict.get(to_user)
            if msg_type == "ai":
                q = baidu_ai.audio2text(file_path)
                print(q)
                ret = baidu_ai.my_nlp(q, tid)
                other_user_socket.send(json.dumps(ret))
            else:
                send_str = {
                    "code": 0,
                    "from_user": tid,
                    "msg_type": "chat",
                    "data": file_name
                }

                if other_user_socket:  # 当websocket连接存在时
                    chat_redis.save_msg(tid, to_user)  # 保存消息到redis
                    # 发送数据
                    other_user_socket.send(json.dumps(send_str))
                else:
                    # 离线消息
                    chat_redis.save_msg(tid, to_user)

                # 保存聊天记录到MongoDB
                _add_chat(tid, to_user, send_str.get("data"))

            to_user = ""
            file_name = ""


@app.route("/app/<uid>")
def user_app(uid):  # 手机app连接
    user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
    if user_socket:
        user_socket_dict[uid] = user_socket
        # { uid : websocket}
        print(user_socket_dict)

    file_name = ""
    to_user = ""

    while True:  # 手机听歌 把歌曲发送给 玩具 1.将文件直接发送给玩具 2.将当前听的歌曲名称或ID发送到玩具
        msg = user_socket.receive()
        if type(msg) == bytearray:  # 判断类型为bytearray
            file_name = f"{uuid4()}.amr"  # 文件后缀为amr,安卓和ios通用
            file_path = os.path.join(CHAT_FILE, file_name)  # 存放在chat目录
            print(msg)
            with open(file_path, "wb") as f:
                f.write(msg)  # 写入文件

            # 将amr转换为mp3,因为html中的audio不支持amr
            os.system(f"ffmpeg -i {file_path} {file_path}.mp3")

        else:
            msg_dict = json.loads(msg)
            to_user = msg_dict.get("to_user")  # 获取目标用户

            if msg_dict.get("msg_type") == "music":
                other_user_socket = user_socket_dict.get(to_user)

                send_str = {
                    "code": 0,
                    "from_user": uid,
                    "msg_type": "music",
                    "data": msg_dict.get("data")
                }
                other_user_socket.send(json.dumps(send_str))

            # res = content._content_one(content_id)
        if file_name and to_user:  # 如果文件名和发送用户同上存在时
            # 查询玩具信息
            res = setting.MONGO_DB.toys.find_one({"_id": ObjectId(to_user)})
            # 获取friend_remark
            fri = [i.get("friend_remark") for i in res.get("friend_list") if i.get("friend_id") == uid][0]
            msg_file_name = baidu_ai.text2audio(f"你有来自{fri}的消息")

            # 获取websocket对象
            other_user_socket = user_socket_dict.get(to_user)
            # 构造数据
            send_str = {
                "code": 0,
                "from_user": uid,
                "msg_type": "chat", # 聊天类型
                # 后缀必须是mp3的
                "data": msg_file_name
            }
            if other_user_socket:
                chat_redis.save_msg(uid, to_user)
                # 发送数据给前端页面
                other_user_socket.send(json.dumps(send_str))
            else:
                # 保存redis
                chat_redis.save_msg(uid, to_user)

            # 添加聊天记录到数据库
            _add_chat(uid, to_user, f"{file_name}.mp3")
            # 最后一定要清空这2个变量,否则造成混乱
            file_name = ""
            to_user = ""

def _add_chat(sender, to_user, msg):  # 添加聊天记录到数据库
    chat_window = setting.MONGO_DB.chat.find_one({"user_list": {"$all": [sender, to_user]}})
    if not chat_window.get("chat_list"):
        chat_window["chat_list"] = [{
            "sender": sender,
            "msg": msg,
            "updated_at": time.time(),
        }]
        res = setting.MONGO_DB.chat.update_one({"_id": ObjectId(chat_window.get("_id"))}, {"$set": chat_window})
    else:
        chat = {
            "sender": sender,
            "msg": msg,
            "updated_at": time.time(),
        }
        res = setting.MONGO_DB.chat.update_one({"_id": ObjectId(chat_window.get("_id"))}, {"$push": {"chat_list": chat}})

    return res

if __name__ == '__main__':
    # 创建一个WebSocket服务器
    http_serv = WSGIServer(("0.0.0.0", 9528), app, handler_class=WebSocketHandler)
    # 开始监听HTTP请求
    http_serv.serve_forever()


'''
{
    "code": 0,
    "from_user": uid,  # APP用户id
    "data": music_name  # 歌曲名
}
'''
View Code

 

给小甜甜发送消息,可能不止一条。后端收取消息,要有多条

 

修改 serv-->chat.py,改为[-count:] 。如果是2条,就是[-2:]。表示最后2条!

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from flask import Blueprint, request, jsonify
from setting import MONGO_DB
from setting import RET
from bson import ObjectId
from utils import chat_redis

cht = Blueprint("cht", __name__)


@cht.route("/chat_list", methods=["POST"])
def chat_list():  # 聊天记录列表
    user_id = request.form.get("user_id")
    friend_id = request.form.get("friend_id")
    print(friend_id)

    chat_window = MONGO_DB.chat.find_one({"user_list": {"$all": [user_id, friend_id]}})
    fri = MONGO_DB.toys.find_one({"_id": ObjectId(friend_id)})
    baby_name = fri.get("baby_name")
    cl = chat_window.get("chat_list")

    RET["code"] = 0
    RET["msg"] = baby_name
    RET["data"] = cl

    # 获取用户单个好友记录,修改redis的值
    chat_redis.get_user_msg_one(friend_id,user_id)

    return jsonify(RET)


@cht.route("/get_msg", methods=["POST"])
def get_msg():  # 获取聊天语言文件
    user_id = request.form.get("user_id")
    sender = request.form.get("sender")
    count = 1  # 初始值
    if not sender:
        msg_dict = chat_redis.get_msg_list(user_id)
        print(msg_dict,"msg_dict")
        sender = list(msg_dict.keys())[0]
        count = msg_dict[sender]
    else:
        # 获取用户某个好友的值
        count = chat_redis.get_user_msg_one(sender,user_id)

    # $all 表示多个条件都成立时。这里表示user_list字段中user_id和sender必须都存在才行!
    chat_window = MONGO_DB.chat.find_one({"user_list": {"$all": [user_id, sender]}})
    # [-count:] 表示获取最后的几条消息。比如: -1: 表示最后一条
    new_msg = chat_window.get("chat_list")[-count:]

    RET["code"] = 0
    RET["msg"] = ""
    RET["data"] = new_msg

    # chat_redis.get_user_msg_one(sender,user_id)

    return jsonify(RET)

@cht.route("/get_msg_list", methods=["POST"])
def get_msg_list():
    user_id = request.form.get("user_id")
    user_msg_dict = chat_redis.get_msg_list(user_id)

    RET["code"] = 0
    RET["msg"] = ""
    RET["data"] = user_msg_dict

    return jsonify(RET)
View Code

 

 修改 utils-->chat_redis.py

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from setting import REDIS_DB
import json


def save_msg(sender, to_user):  # 保存消息
    # 1.查询一下xiao的Redis是否有数据
    user_msg_redis = REDIS_DB.get(to_user)
    if user_msg_redis:
        # 2.将xiao的数据反序列化成字典 { sender : n }
        user_msg_dict = json.loads(user_msg_redis)
        # 3.判断有没有 sender 的用户发来的消息数量
        if user_msg_dict.get(sender):
            # 数量加1
            user_msg_dict[sender] += 1
        else:
            # 第一次,初始值为1
            user_msg_dict[sender] = 1
    # 4.如果xiao是刚建立好的用户,他是没有消息的,字典是空
    else:
        user_msg_dict = {sender: 1}

    # 5.序列化用户消息字典user_msg_dict
    user_msg_redis = json.dumps(user_msg_dict)
    # 6.存回Redis
    REDIS_DB.set(to_user, user_msg_redis)

def get_msg_list(user):  # 获取消息
    user_msg_redis = REDIS_DB.get(user)
    if user_msg_redis:
        user_msg_dict = json.loads(user_msg_redis)
        # 统计数量
        user_msg_dict["count"] = sum(user_msg_dict.values())
    else:
        user_msg_dict = {"count":0}

    return user_msg_dict

def get_user_msg_one(sender, to_user):  # 获取用户一个好友消息
    user_msg_redis = REDIS_DB.get(to_user)
    if user_msg_redis:
        user_msg_dict = json.loads(user_msg_redis)
        if user_msg_dict.get(sender):
            return user_msg_dict.get(sender)
            # user_msg_dict[sender] = 0

    else:
        user_msg_dict = {sender:0}

    user_msg_redis = json.dumps(user_msg_dict)
    REDIS_DB.set(to_user,user_msg_redis)  # 修改redis
View Code

 

修改index.html,使用player.onended。它会接收多条

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
<!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 οnclick="start_toy()">玩具开机键</button>
<br>
<button οnclick="start_reco()">开始废话</button>
<br>
<button οnclick="stop_reco()">发送语音</button>
<br>
<button οnclick="start_reco()">录制消息</button>
<span id="to_user"></span>
<br>
<button οnclick="send_reco()">发送语音消息</button>
<br>
<button οnclick="recv_msg()">收取消息</button>
</body>
<script src="/static/recorder.js"></script>
<script src="/static/jquery.min.js"></script>
<script type="application/javascript">
    var serv = "http://127.0.0.1:9527";
    var ws_serv = "ws://127.0.0.1:9528";

    // 获取音频文件
    var get_music = serv + "/get_audio/";
    var get_chat = serv + "/get_chat/";

    var ws = null;  // WebSocket 对象
    var reco = null;
    // 创建AudioContext对象
    var audio_context = new AudioContext();

    var toy_id = null;

    //要获取音频和视频
    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 send_reco() {
        reco.stop();
        send_audio();
        reco.clear();
    }

    function send_audio() {
        var to_user = document.getElementById("to_user").innerText;
        var send_str = {
            "to_user": to_user
        };
        ws.send(JSON.stringify(send_str));
        reco.exportWAV(function (wav_file) {
            ws.send(wav_file);
        })
    }

    function get_audio() {

        var send_str = {
            "to_user": toy_id,
            "msg_type": "ai"
        };
        ws.send(JSON.stringify(send_str));
        reco.exportWAV(function (wav_file) {
            ws.send(wav_file);
        })
    }


    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_music + data.data.audio;
                if (toy_id) {  // 判断玩具id存在时
                    ws = new WebSocket(ws_serv + "/toy/" + toy_id);
                    ws.onmessage = function (data) {
                        // console.log(get_music + data.data);
                        var content = JSON.parse(data.data);  //反序列化数据
                        // 判断消息类型
                        if (content.msg_type == "chat") {
                            document.getElementById("player").src = get_chat + content.data;
                            document.getElementById("to_user").innerText = content.from_user;
                            console.log(content.from_user + "给你发送了一条消息");
                        }
                        if (content.msg_type == "music") {
                            document.getElementById("player").src = get_music + content.data;
                            console.log(content.from_user + "给你点播了歌儿");
                        }
                    };
                    ws.onclose = function () {
                        window.location.reload();
                    }
                }
            }, "json"
            // 规定预期的服务器响应的数据类型为json
        );
    }

    function recv_msg() {
        var to_user = document.getElementById("to_user").innerText;
        var player = document.getElementById("player");

        to_user = document.getElementById("to_user").innerText;
        $.post(
            serv + "/get_msg",
            {user_id: toy_id, sender: to_user},
            function (data) {
                // shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值
                var msg = data.data.shift();
                document.getElementById("to_user").innerText = msg.sender;
                player.src = get_chat + msg.msg;  //修改audio标签src属性
                // onended 事件在视频/音频(audio/video)播放结束时触发
                player.onended = function () {
                    // 如果长度大于0,也就是有1条或者多条时
                    if(data.data.length > 0){
                        //修改audio标签src属性,有多条时,会轮询触发
                       player.src = get_chat + data.data.shift().msg;
                    }else{
                       return null;
                    }
                }
            }, "json"
        )
    }


</script>
</html>
View Code

重启 manager.py和im_serv.py

 

重新访问网页,让玩具开机。连续录制2个语音

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

再点击收取消息,网页会先播放一条,再紧着播放第二条!

 

二、玩具端消息推送

APP发送语音后,页面语音提示,你有来自 xx 的消息

 

修改 serv-->chat.py,修改get_msg视图函数

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
from flask import Blueprint, request, jsonify
from setting import MONGO_DB
from setting import RET
from bson import ObjectId
from utils import chat_redis

cht = Blueprint("cht", __name__)


@cht.route("/chat_list", methods=["POST"])
def chat_list():  # 聊天记录列表
    user_id = request.form.get("user_id")
    friend_id = request.form.get("friend_id")
    print(friend_id)

    chat_window = MONGO_DB.chat.find_one({"user_list": {"$all": [user_id, friend_id]}})
    fri = MONGO_DB.toys.find_one({"_id": ObjectId(friend_id)})
    baby_name = fri.get("baby_name")
    cl = chat_window.get("chat_list")

    RET["code"] = 0
    RET["msg"] = baby_name
    RET["data"] = cl

    # 获取用户单个好友记录,修改redis的值
    chat_redis.get_user_msg_one(friend_id,user_id)

    return jsonify(RET)


@cht.route("/get_msg", methods=["POST"])
def get_msg():  # 获取聊天语言文件
    user_id = request.form.get("user_id")
    sender = request.form.get("sender")
    count = 1  # 初始值
    if not sender:
        msg_dict = chat_redis.get_msg_list(user_id)
        # print(msg_dict,"msg_dict")
        # 未读数量
        sender = [i for i in msg_dict.keys() if msg_dict[i] != 0 and i != "count"]
        if sender:
            sender = sender[0]
            count = msg_dict[sender]
        else:
            pass  # 没有任何消息了,可以调用合成语言,提示一下
            # filename= baidu_ai.text2audio("")
            # new_msg = [{sender:"",msg:filename}]
    else:
        # 获取用户某个好友的值
        count = chat_redis.get_user_msg_one(sender,user_id)

    # $all 表示多个条件都成立时。这里表示user_list字段中user_id和sender必须都存在才行!
    chat_window = MONGO_DB.chat.find_one({"user_list": {"$all": [user_id, sender]}})
    # [-count:] 表示获取最后的几条消息。比如: -1: 表示最后一条
    new_msg = chat_window.get("chat_list")[-count:]
    # 这里可以提示,您收到来自xx的几条消息
    # filename= baidu_ai.text2audio("")
    # new_msg.insert(0,{
    #     "sender":sender,
    #     "msg":filename
    # })

    RET["code"] = 0
    RET["msg"] = ""
    RET["data"] = new_msg

    chat_redis.get_user_msg_one(sender,user_id)

    return jsonify(RET)

@cht.route("/get_msg_list", methods=["POST"])
def get_msg_list():
    user_id = request.form.get("user_id")
    user_msg_dict = chat_redis.get_msg_list(user_id)

    RET["code"] = 0
    RET["msg"] = ""
    RET["data"] = user_msg_dict

    return jsonify(RET)
View Code

重启 manager.py和im_serv.py

 

使用App发送2条消息

python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

玩具页面会有语音提示,你有来自 小鱼的消息

点击收取消息。会自动播放2条语音!

 python 全栈开发,Day131(向app推送消息,玩具端消息推送)

 

今日总结:

python 全栈开发,Day131(向app推送消息,玩具端消息推送)python 全栈开发,Day131(向app推送消息,玩具端消息推送)
1.向app推送消息
    Redis 中存储消息:
        to_user : { sender : 1 }
        
    消息按钮 未读消息
        在message点击打开 chat_window的时候 发起一个fire(cut)事件给index页面
        index页面 根据 cut 值进行删减 角标的数字
        
    chat_window 未读消息
        message页面将未读消息数字置空 = 0 
        chat_window 页面 发起的 chat_list 请求,加入逻辑 将redis中的未读消息置空 = 0
    
2.玩具端消息推送
    消息列表 - 区分用户
    array.shift()    删除array中的第一个元素并返回
    批量收取一个用户的消息
    AudioContext.onended = function(){
        AudioContext.src = "music.mp3"
    }
    
    批量收取消息的逻辑:
        1.从sender未读消息中拿出未读数量 未读数量不是 0 
        2.从chat_list中拿出最后的几条未读消息
View Code

 

完整代码,参考github:

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

 

posted @ 2018-09-21 15:25 肖祥 阅读(...) 评论(...) 编辑 收藏