在线聊天室优化之私聊

简介: 在线聊天室优化之私聊

这篇文章距离上一次写在线聊天室系列的最后一篇已经有五个月了,当时就留下了很多坑,比如页面优化,权限优化等等功能都没有做。这期间懒癌附体,一直给自己各种理由去推脱,直到有一天,一位小伙伴来找我,说让我再实现一些高级功能,我才知道原来还真有人会用我的代码,哈哈,立刻就有干劲了有木有。

不过到年底了,确实有点忙(为自己的菜强行找借口),匆忙之间代码写的有点渣,不过还是先实现了私聊的功能。

实现思路

对于私聊,我觉得应该有如下两点需要实现

  • 私聊列表更新
    每个人都需要有一个私聊的列表,并且需要准实时的更新,这样这个人才能知道当前谁准备和自己私聊,以及自己正在私聊的人。
  • 私聊聊天室
    对于私聊的聊天室,其实可以复用群聊的聊天室实现,只不过这个聊天室里只有两个人而已。同时对于消息的传递,同样可以复用群聊中实现的功能。

前端布局

那么既然思路有了,首先就开始布局。这一点对于一个半残前端来说,太楠楠楠了,搞了好久了,只整出这么个布局,略丑,但是也没办法了。

对于不会调样式的我来说,只能对原有的 CSS 代码做些简单的修改了

在原来所有用户列表旁增加一个私聊列表

<div class="chat_pleft">
          <ul class="puser_list" title="" id="pchat">
              <li class="fn-clear selected"><em id="pall">所有私聊</em></li>
              <li class="fn-clear" data-id="112" id="private"><span></span><em>暂时没有任何私聊</em></li>
          </ul>
      </div>

然后再通过调整控件的宽度,来使得新增的 div 显示在聊天框旁边,而不是在下边

.chat_left{ padding:20px; width:-moz-calc(100% - 440px); }
.chat_right{ width:199px; }
.chat_pleft{ width:199px; }

好了,页面布局就说这么多,说多了都是泪。

私聊聊天室

现在开始编写后端逻辑,首先我们要先有一个私聊的聊天室,那么先来改造下 create_room 函数,创建私聊

@main.route('/createroom/', methods=["GET", 'POST'])
@login_required
def create_room(chatwith=None):
    if chatwith:
        rname = chatwith
        if r.exists("pchat-" + rname + '-' + current_user.username) is False:
            r.zadd("pchat-" + rname + '-' + current_user.username, current_user.username, 1)
            r.zadd("pchat-" + rname + '-' + current_user.username, rname, 2)
...

当前函数可以接收一个 chatwith 参数,如果该参数不为 None 则在 redis 中创建 pchat 数据,即为私聊聊天室。

接下来创建私聊页面视图函数,这里在后面可以完善成需要某些权限才可以发起私聊

@main.route('/privatechat/', methods=['GET', 'POST'])
@login_required
def private_chat():
    # 后面可以增加私聊权限
    user_right = True
    if user_right:
        uname = request.args.get('to', "")
        create_room(chatwith=uname)
        ulist = r.zrange("pchat-" + uname + '-' + current_user.username, 0, -1)
        messages = r.zrange("pmsg-" + uname + '-' + current_user.username, 0, -1, withscores=True)
        msg_list = []
        for i in messages:
            msg_list.append([json.loads(i[0]), time.strftime("%Y/%m/%d %p%H:%M:%S", time.localtime(i[1]))])
        return render_template('privatechat.html', rname=uname, user_list=ulist, msg_list=msg_list)
    else:
        pass

下面还需要一个返回私聊列表的函数

# 获取个人私聊信息
@main.route('/api/pchat/<user>', methods=['GET', 'POST'])
def pchat_info(user):
    pchat = r.keys(pattern='pchat-*')
    pchatlist = []
    for i in pchat:
        i_str = str(i)
        user1 = i_str.split('-', 2)[1]
        if user in i_str:
            pchatlist.append({user1: i_str})
    html = []
    for i in pchatlist:
        html.append(f'<li class="fn-clear"><em id="{list(i.keys())[0]}" onclick="pchat(this.id)">{list(i.values())[0]}</em></li>')
    return json.dumps(html)

这里直接拼接了 HTML 代码并返回,之所以这么做是因为 JavaScript 代码能力过弱,只好在 Python 侧做了。

在写这块代码时,我是深刻的体会到了 Vue 等前端框架的好处,不仅仅是快速搭建 UI,在处理数据等方面也是爽的一米,感兴趣的同学可以去看看我的 Flask + Vue 系列。

最后就是改造发送消息的函数 send_chat

...
        rtype = request.form.get("rtype", "")
        if rtype and rtype == 'p':
            ulist = r.zrange("pchat-" + rname + '-' + current_user.username, 0, -1)
            if current_user.username in ulist:
                body = {"username": current_user.username, "msg": info}
                r.zadd("pmsg-" + rname + '-' + current_user.username, json.dumps(body), time.time())
                socket_send(info, current_user.username)
                data = json.dumps({'code': 200, 'msg': info})
                return data
            else:
                data = json.dumps({'code': 403, 'msg': 'You are not in this room'})
                return data
...

前端需要在 URL 参数中传递 rtype 参数来标识该请求是私聊发出的,其他代码基本复用原来的。

前端改造

首先就是要定时刷新私聊列表

// 定时更新私聊列表
    setInterval(function() {
        $.get("http://127.0.0.1:8889/api/pchat/" + "{{ current_user.username }}",//GET请求的url地址
        function(data,status){
            var roomlist = JSON.parse(data);
            for (var i =0; i<roomlist.length; i++) {
                li_html += roomlist[i];
            }
            console.log(li_html);
            $("#pchat").html(li_html);//更新列表内容
          });
        }, 5000); //定时刷新界面(0.5秒)

这里有一些硬编码,请忽略

接下来就是发起私聊的入口了,这里我设置到了双击某个用户,即可发起私聊

// 用户列表操作
    var fromname = $('#fromname').val();
    var to_uid   = 0; // 默认为0,表示发送给所有用户
    var to_uname = '';
    $('.user_list > li').dblclick(function(){
        to_uname = $(this).find('em').text();
        to_uid   = $(this).attr('data-id');
        var redirect_url = 'http://' + document.domain + ':' + location.port + '/privatechat/?to=' + to_uname;
        if(to_uname == fromname){
            alert('您不能和自己聊天!');
            return false;
        }
        if(to_uname == '所有用户'){
            $("#toname").val('');
            $('#chat_type').text('群聊');
        }else{
            // 新开窗口私聊
            window.open(redirect_url);
        }
        $(this).addClass('selected').siblings().removeClass('selected');
    });

当然,用户也可以单击私聊列表来进入私聊聊天室,因为在后端返回时已经给 em 标签设置了 onclick 事件,这里直接实现事件函数即可

function pchat(id){
        var to_user = id;
        var redirect_url = 'http://' + document.domain + ':' + location.port + '/privatechat/?to=' + to_user;
        window.open(redirect_url);
    }

至此,基本改造完成,可以愉快的私聊喽!

私聊效果

最后阅读原文直达 GitHub 地址哦

相关文章
|
24天前
|
人工智能 自然语言处理 算法
AISEO咋做?2025年用AI优化SEO和GEO 的步骤
AISEO是AI与SEO结合的优化技术,通过人工智能生成关键词、标题、内容等,提升网站排名。它支持多语言、自动化创作,并利用高权重平台发布内容,让AI搜索更易抓取引用,实现品牌曝光与流量增长。
|
7月前
|
JSON 测试技术 API
大模型工程师基础之学会使用openai
本系列教程涵盖OpenAI API基础到高级应用,包括文本生成、图像处理、语音交互、会话管理、流式响应、文件输入、推理模型及性能评估等十大核心功能。适合新手入门与工程师实践,助您掌握大模型开发关键技术。从简单Prompt设计到复杂多模态任务,逐步深入,结合实例代码与最佳实践,提升实际开发能力。希望这些内容对您有帮助!
725 11
|
6月前
|
数据可视化 开发者 智能硬件
鸿蒙5开发宝藏案例分享---一多断点开发实践
本文深入解析鸿蒙开发中的六大核心案例,涵盖动态网格布局、自适应导航栏、阅读器分栏模式、视频播放器多形态适配、数据看板动态布局及表单自动优化。通过具体应用场景与代码实现,解决多端适配痛点,如手机单列到平板多列的智能计算、折叠屏半开状态特殊布局等。同时提供开发者避坑指南与终极适配方案架构,帮助开发者灵活应对复杂需求,提升开发效率。
|
6月前
|
JSON 缓存 程序员
玩转HarmonyOS NEXT网络请求:从新手到高手的实战秘籍
本文以通俗易懂的方式讲解了HarmonyOS网络请求的核心知识,从基础概念到实战技巧,再到进阶优化,帮助开发者快速上手。通过“点外卖”的类比,形象解释了HTTP请求方法(如GET、POST)和JSON数据格式的作用。同时,提供了封装工具类的示例代码,简化重复操作,并分享了常见问题的解决方法(如权限配置、参数格式、内存泄漏等)。最后,还探讨了如何通过拦截器、缓存机制和重试机制提升请求功能。无论你是新手还是进阶开发者,都能从中受益,快动手实现一个新闻App试试吧!
354 5
|
存储 网络协议 Ubuntu
【Linux开发实战指南】基于UDP协议的即时聊天室:快速构建登陆、聊天与退出功能
UDP 是一种无连接的、不可靠的传输层协议,位于IP协议之上。它提供了最基本的数据传输服务,不保证数据包的顺序、可靠到达或无重复。与TCP(传输控制协议)相比,UDP具有较低的传输延迟,因为省去了建立连接和确认接收等过程,适用于对实时性要求较高、但能容忍一定数据丢失的场景,如在线视频、语音通话、DNS查询等。 链表 链表是一种动态数据结构,用于存储一系列元素(节点),每个节点包含数据字段和指向下一个节点的引用(指针)。链表分为单向链表、双向链表和循环链表等类型。与数组相比,链表在插入和删除操作上更为高效,因为它不需要移动元素,只需修改节点间的指针即可。但访问链表中的元素不如数组直接,通常需要从
554 2
|
存储 Java API
Spring揭秘:Environment接口应用场景及实现原理!
Environment接口提供了强大且灵活的环境属性管理能力,通过它,开发者能轻松地访问和配置应用程序运行时的各种属性,如系统属性、环境变量等。 同时,Environment接口还支持属性源的定制和扩展,使得开发者能根据实际需求灵活地定制属性的加载和解析方式。
407 1
Spring揭秘:Environment接口应用场景及实现原理!
|
Java
Java 实现 植物大战僵尸 小游戏【附源码】
Java 实现 植物大战僵尸 小游戏【附源码】
506 3
|
Rust 监控 安全
【专栏】`ripgrep`(rg)是Linux下快速、内存高效的文本搜索工具,用Rust编写,支持PCRE2正则表达式
【4月更文挑战第28天】`ripgrep`(rg)是Linux下快速、内存高效的文本搜索工具,用Rust编写,支持PCRE2正则表达式。相比`grep`,它在处理大文件和复杂模式时更具优势。安装`rg`可通过软件包管理器,如在Debian系系统中使用`sudo apt install ripgrep`。基本用法包括简单搜索、递归搜索、忽略大小写、显示行号等。高级功能包括固定字符串搜索、多文件匹配、并行搜索、排除选项和区域搜索。适用于日志分析、代码审查等场景,是提升工作效率的利器。
1498 4
|
定位技术 数据处理 Python
Anaconda环境GDAL库基于whl文件的配置方法
Anaconda环境GDAL库基于whl文件的配置方法
430 1