今天我们要做的就是基于websocket实时人工客服,先来了解一下机制
WebSocket 机制
WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
- WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
- WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。
那我们知道可为什么要使用它了吧
django后端接口
表的设计
# 聊天表
class Chat(models.Model):
user_id_a = models.IntegerField()
user_id_b = models.IntegerField()
class Meta:
index_together = ['user_id_a', 'user_id_b']
unique_together = ['user_id_a', 'user_id_b']
# 联合索引要这样写入!!!!!!!!!
db_table = '聊天表'
# 消息表
class Message(models.Model):
name = models.CharField(max_length=32, null=True)
message = models.CharField(max_length=132)
chat = models.ForeignKey(Chat, on_delete=models.CASCADE)
class Meta:
db_table = '消息表'
views.py
from dwebsocket.decorators import accept_websocket
from .serializers import *
from .models import *
# 接收前端信息
@accept_websocket
def reception_socket(request):
if request.is_websocket():
for message in request.websocket:
input_text = eval(str(message, encoding='utf-8'))
username = input_text.get("username")
uid = input_text.get("uid")
input_text = input_text.get("inputText")
try:
chat = Chat.objects.create(user_id_a=uid, user_id_b=998)
Message.objects.create(message=input_text, chat=chat, name=username)
except:
chat_id = Chat.objects.get(user_id_a=uid, user_id_b=998)
Message.objects.create(message=input_text, chat=chat_id, name=username)
request.websocket.send(message)
# 主动推送消息
@accept_websocket
def send_websocket(request):
uid = request.GET.get("uid")
if request.is_websocket():
while 1:
time.sleep(1) ## 向前端发送时间
try:
data = Chat.objects.get(user_id_a=uid, user_id_b=998)
ser = MessageModelSerializer(Message.objects.filter(chat_id=data.id), many=True)
request.websocket.send(json.dumps(ser.data))
except:
request.websocket.send(json.dumps([{"message": ""}]))
urls.py
from django.urls import path, include
from .views import *
urlpatterns = [
path('reception_socket/', reception_socket), # 客服系统接收前端信息
path('send_websocket/', send_websocket), #客服发送消息
]
VUE前端
客户页面 staff_service.vue
我这里封装为组件了 你也可以给个路由成为一个单独的页面
<template>
<div>
<div>
<a-button type="primary" @click="showDrawer">
<a-icon type="plus"/>
人工客服
</a-button>
<a-drawer
title="翔翔客服带给您最好的体验"
:width="720"
:visible="visible"
:body-style="{ paddingBottom: '80px' }"
@close="onClose(false)"
>
<a-row :gutter="16">
<table>
<tr v-for="i in message">
<th>{{i.name}}:</th>
<td>{{ i.message }}</td>
</tr>
</table>
</a-row>
<a-form :form="form" layout="vertical" hide-required-mark>
<a-row :gutter="16">
<a-col :span="24">
<a-form-item label="Description">
<a-textarea
v-model="inputText"
:rows="4"
placeholder="请输入问题描述"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
<div
:style="{
position: 'absolute',
right: 0,
bottom: 0,
width: '100%',
borderTop: '1px solid #e9e9e9',
padding: '10px 16px',
background: '#fff',
textAlign: 'right',
zIndex: 1,
}"
>
<a-button :style="{ marginRight: '8px' }" @click="onClose(false)">
Cancel
</a-button>
<a-button type="primary" @click="onClose(true)">
Submit
</a-button>
</div>
</a-drawer>
</div>
</div>
</template>
<script>
import md5 from 'js-md5';
import echarts from "echarts";
export default {
name: "staff_service",
data() {
return {
form: this.$form.createForm(this),
visible: false,
inputText: '',
username: localStorage.getItem("username"),
uid: localStorage.getItem("id"),
message: [],
};
},
methods: {
showDrawer() {
this.visible = true;
},
onClose(ok) {
this.visible = ok;
if (ok === true) {
var ed2020 = "2020";
var sign = md5('price=500&goodid=3,1' + ed2020);
console.log(sign);
var _this = this;
//判断浏览器是否支持websocket
if ("WebSocket" in window) {
console.log("支持");
//生成websocket链接
var ws = new WebSocket("ws://localhost:8000/user/reception_socket/");
//发送链接请求
ws.onopen = function () {
var data = JSON.stringify({username: _this.username, inputText: _this.inputText, uid: _this.uid})
ws.send(data);
}
//发送消息
ws.onmessage = function (evt) {
//将获取信息打印
var received_msg = evt.data;
// alert(received_msg);
}
//捕获断开链接
ws.onclose = function () {
console.log("链接已经关闭");
}
}
}
},
},
mounted() {
// this.main()
var ed2020 = "2020";
var sign = md5('price=500&goodid=3,1' + ed2020);
console.log(sign);
var _this = this;
//判断浏览器是否支持websocket
if ("WebSocket" in window) {
console.log("支持");
//生成websocket链接
var ws = new WebSocket("ws://localhost:8000/user/send_websocket/?uid=" + _this.uid);
//发送链接请求
ws.onopen = function () {
ws.send("text");
}
//发送消息
ws.onmessage = function (evt) {
//将获取信息打印
var received_msg = evt.data;
var data
var data2
data = JSON.parse(received_msg)
_this.message = data
// data = JSON.parse(data)
// console.log(data[0])
}
//捕获断开链接
ws.onclose = function () {
console.log("链接已经关闭");
}
}
}
}
</script>
<style scoped>
</style>
客服页面service.vue
需要设置路由 客服是一个单独的页面
<template>
<div>
<div>
<a-button type="primary" @click="showDrawer">
<a-icon type="plus"/>
人工客服
</a-button>
<a-drawer
title="翔翔客服带给您最好的体验"
:width="720"
:visible="visible"
:body-style="{ paddingBottom: '80px' }"
@close="onClose(false)"
>
<a-row :gutter="16">
<table>
<tr v-for="i in message">
<th>{{i.name}}:</th>
<td>{{ i.message }}</td>
</tr>
</table>
</a-row>
<a-form :form="form" layout="vertical" hide-required-mark>
<a-row :gutter="16">
<a-col :span="24">
<a-form-item label="Description">
<a-textarea
v-model="inputText"
:rows="4"
placeholder="请输入问题描述"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
<div
:style="{
position: 'absolute',
right: 0,
bottom: 0,
width: '100%',
borderTop: '1px solid #e9e9e9',
padding: '10px 16px',
background: '#fff',
textAlign: 'right',
zIndex: 1,
}"
>
<a-button :style="{ marginRight: '8px' }" @click="onClose(false)">
Cancel
</a-button>
<a-button type="primary" @click="onClose(true)">
Submit
</a-button>
</div>
</a-drawer>
</div>
</div>
</template>
<script>
import md5 from 'js-md5';
import echarts from "echarts";
export default {
name: "staff_service",
data() {
return {
form: this.$form.createForm(this),
visible: false,
inputText: '',
username: localStorage.getItem("username"),
uid: localStorage.getItem("id"),
message: [],
};
},
methods: {
showDrawer() {
this.visible = true;
},
onClose(ok) {
this.visible = ok;
if (ok === true) {
var ed2020 = "2020";
var sign = md5('price=500&goodid=3,1' + ed2020);
console.log(sign);
var _this = this;
//判断浏览器是否支持websocket
if ("WebSocket" in window) {
console.log("支持");
//生成websocket链接
var ws = new WebSocket("ws://localhost:8000/user/reception_socket/");
//发送链接请求
ws.onopen = function () {
var data = JSON.stringify({username: "客服", inputText: _this.inputText, uid: _this.uid})
ws.send(data);
}
//发送消息
ws.onmessage = function (evt) {
//将获取信息打印
var received_msg = evt.data;
// alert(received_msg);
}
//捕获断开链接
ws.onclose = function () {
console.log("链接已经关闭");
}
}
}
},
},
mounted() {
// this.main()
var ed2020 = "2020";
var sign = md5('price=500&goodid=3,1' + ed2020);
console.log(sign);
var _this = this;
//判断浏览器是否支持websocket
if ("WebSocket" in window) {
console.log("支持");
//生成websocket链接
var ws = new WebSocket("ws://localhost:8000/user/send_websocket/?uid=" + _this.uid);
//发送链接请求
ws.onopen = function () {
ws.send("text");
}
//发送消息
ws.onmessage = function (evt) {
//将获取信息打印
var received_msg = evt.data;
var data
var data2
data = JSON.parse(received_msg)
_this.message = data
// data = JSON.parse(data)
// console.log(data[0])
}
//捕获断开链接
ws.onclose = function () {
console.log("链接已经关闭");
}
}
}
}
</script>
<style scoped>
</style>
最终效果
ok 今天的学习就到这里了
觉得文章写的不错,可以请喝杯咖啡
- Post link: https://yanxiang.wang/django-vue%E5%9F%BA%E4%BA%8Ewebsocket%E4%BA%BA%E5%B7%A5%E5%AE%A2%E6%9C%8D%E7%B3%BB%E7%BB%9F%E6%89%93%E9%80%A0/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.