这篇文章距离上一次写在线聊天室系列的最后一篇已经有五个月了,当时就留下了很多坑,比如页面优化,权限优化等等功能都没有做。这期间懒癌附体,一直给自己各种理由去推脱,直到有一天,一位小伙伴来找我,说让我再实现一些高级功能,我才知道原来还真有人会用我的代码,哈哈,立刻就有干劲了有木有。
不过到年底了,确实有点忙(为自己的菜强行找借口),匆忙之间代码写的有点渣,不过还是先实现了私聊的功能。
实现思路
对于私聊,我觉得应该有如下两点需要实现
- 私聊列表更新
每个人都需要有一个私聊的列表,并且需要准实时的更新,这样这个人才能知道当前谁准备和自己私聊,以及自己正在私聊的人。 - 私聊聊天室
对于私聊的聊天室,其实可以复用群聊的聊天室实现,只不过这个聊天室里只有两个人而已。同时对于消息的传递,同样可以复用群聊中实现的功能。
前端布局
那么既然思路有了,首先就开始布局。这一点对于一个半残前端来说,太楠楠楠了,搞了好久了,只整出这么个布局,略丑,但是也没办法了。
对于不会调样式的我来说,这能对原有的 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 地址在这里:https://github.com/zhouwei713/online-chat
共同学习,写下你的评论
评论加载中...
作者其他优质文章