websoket
2021-09-02 本文已影响0人
为了_理想
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="/Public/Css/imWeb.css">
<title></title>
<style>
[v-cloak] {
display: none;
}
.imWeb_backImg{
width: 20px;
}
</style>
</head>
<body>
<div class="imWeb" v-cloak>
<div class="imWeb_header">
<header class="imWeb_kefu_header">
<div class="imWeb_header_left" @click="callBack">
<img v-if="userInfo.client!='miniapp'" class="imWeb_backImg" src="/Public/images/choseIfm.png" alt="">
</div>
<div>
{{activeObj.nickname}}
<span class="on_line_status">{{on_line ? '在线' : '离线'}}</span>
</div>
<div class="imWeb_header_right" >
<img @click="clickKehu" ref="kehuMenuImg" class="imWeb_kehuImg" v-if="kefuList.length>1"
:src="isNextOpen ? '/Public/images/imWeb_kehuMenu.png' : '/Public/images/imWeb_ColorKehuMenu.png'"
alt="">
</div>
</header>
</div>
<div class="imWeb_main">
<div ref="imWebPopup" v-if="isShowPopUp">
<div ref="popup" class="imWeb_popup">
<div class="imWeb_popup_right_list" ref="imWeb_popup_right_list">
<div @click="clickehuList(item, index)"
:class="item.is_chose ? 'imWeb_popup_right_list_box_active' : 'imWeb_popup_right_list_box'"
v-for="(item,index) in kefuList" :key="index">
<div class="imWeb_popup_right_list_left">
<img style="border-radius: 40%;" src="/Public/images/kefu.jpg" alt="">
</div>
<div class="imWeb_popup_right_list_right">
<div>{{item.nickname}}</div>
<div class="imWeb_popup_right_list_right_messge">
<span style="color:red" v-if="item.has_new_msg">收到新信息</span>
{{item.content}}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="imWeb_main_center" ref="imWeb_main_center">
<div class="chatPage_right_main" ref="chatPage_right_main_ref" @click="closeMainBox">
<!-- @click="closeFy(item,index)" -->
<div class="chatPage_messge_main_box" ref="chatPage_right_main_ref_for" v-for="(item,index) in nowMsg" :key="index">
<div class="chatPage_right_main_left" v-if="item.is_main == 2" >
<div class="chat_header_box">
<img style="border-radius:35%;" src="/Public/images/kefu.jpg" alt="">
</div>
<div style="max-width: 55%;">
<div class="message" @click.stop="translate(item,index)" v-if="item.type == 0">
{{item.content}}
</div>
<div v-if="item.translation_content">
<div class="translate_box_left_right">
{{item.translation_content}}
</div>
</div>
</div>
<div class="message" v-if="item.type == 1">
<img @click="clickImages(item)" style="width:60px;user-select:none;" :src="item.content"
alt="">
</div>
<div ref="translate_box" class="translate_box" v-if="activeFy == index && clickTranslate">
<div class="translate_box_main">
<div class="translate_box_left" @click.stop="translateItem(item,index,'en')">
<div style="margin-top:6px;user-select:none;">
<img src="/Public/images/imWeb_english.png" alt="">
</div>
中=>英
</div>
<div class="translate_box_left" @click.stop="translateItem(item,index,'zh')">
<div style="margin-top:6px;user-select:none;">
<img src="/Public/images/imWeb_chinese.png" alt="">
</div>
en=>zh
</div>
</div>
</div>
</div>
<div class="chatPage_left_main_left" v-if="item.is_main == 1">
<div class="chat_header_box_right">
<div class="messageRight" v-if="item.type == 0">
<div v-if="item.is_upload == 1">
<img style="width:60px;user-select:none;" @click="clickImages(item)"
:src="item.content" alt="">
</div>
<div v-else>
{{item.content}}
</div>
</div>
<div class="messageRight" v-if="item.type == 1">
<img style="width:60px;user-select:none;" @click="clickImages(item)"
:src="item.content" alt="">
</div>
</div>
<div class="messageRight_headerImg">
<img src="/Public/images/kehu.png" alt="">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="imWeb_main_center_footer">
<div class="imWeb_main_center_footer_box">
<div class="upFile">
<input @change="getFile($event)" id="upload-input" type="file" multiple
accept="image/gif, image/jpg, image/png" />
<img id="imWeb_main_center_footer_upfile" src="/Public/images/imWebSendMessge.png" />
</div>
<textarea v-model="notedata" ref="textareaRef" @keydown="sendMessge('keydown')"
id="imWeb_main_center_footer_textarea"></textarea>
<div class="openMessge" @click="sendMessge('messge')">
<div class="configMessge">发送</div>
</div>
</div>
</div>
<div class="showPopupImg" v-if="is_showPopupImg">
<div class="showPopupImgMain" @click="closePopupImg">
<img ref="popupImg" :src="itemPopupImg" alt="">
</div>
</div>
</div>
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript" src="/Public/Js/vue.min.js"></script>
<script>
const vm = new Vue({
el: ".imWeb",
data: {
/*
@params
userInfo = {
uid, 用户uid
path: sanhuo or diamond 来自哪个页面 散货页面或者裸钻页面
content: null 默认输入聊天框的内容
client: mobile or miniapp or pc 来自哪个页面
}
*/
userInfo: {$userinfo},
wsUrl: "{$im_address}",
isNextOpen: true, //判断是否已经打开了
flag: true,//禁止多次点击
kefuList: [], //与当前客服聊天的客户
activeObj: {},//当前客服的信息
notedata: "",//发送的聊天信息
fileResult: '',//发送的图片
timmer: '',//定时器ID
closeTimmer: false,//是否关闭定时器
nowMsg: [],//当前用户发送的信息
storage_key: "",//当前客户的uid
activePage: 1, //page 页数
is_next: true,//用来判断是否可以继续上拉加载
on_line: false,//是否在线
is_showPopupImg: false, //用来显示全屏图片
itemPopupImg: '', //点击显示的图片
isShowPopUp: false,//用来显示右侧弹出层
activeFy: "",//翻译
timerId: '',//翻译定时器启动的ID
clickTranslate: false,
iframeData:{},//向嵌套进来的页面发送的信息对象
},
watch: {
activeObj: function (newVal, oldVal) {
this.showLine(newVal)
this.getMessage(newVal, this.activePage)
},
},
mounted() {
var that = this
var t = null
this.$refs.chatPage_right_main_ref.addEventListener("scroll", function () {
if (t === null) {
t = setTimeout(() => {
if (that.$refs.chatPage_right_main_ref.scrollTop == 0 && that.is_next) {
that.is_next = false
that.activePage++
that.getMessage(that.activeObj, that.activePage)
}
t = null
}, 30)
}
})
window.addEventListener("message", function(event){
that.scrollToBottom()
var data = event.data;
console.log(data.params)
switch (data.cmd) {
case 'getFormJson': // 处理业务逻辑
if(that.userInfo.client == 'mobile' && data.params.content){
that.notedata = data.params.content
}
break;
}
});
},
created() {
if(this.userInfo.content){
this.notedata = this.userInfo.content
}
var that = this
this.storage_key = this.userInfo.path + '_' + this.userInfo.uid
this.user_key = this.userInfo.path + "_" + this.userInfo.uid + '_' + this.userInfo.is_supply
this.connectIm() //获取聊天响应数据
},
methods: {
callBack(){
window.parent.postMessage({
cmd: 'callBack',
params:{
closeImWeb:true
}
}, '*');
},
clickImages(item) {
this.is_showPopupImg = !this.is_showPopupImg
this.itemPopupImg = item.content
},
closePopupImg() {
this.is_showPopupImg = false
this.itemPopupImg = ''
},
connectIm() {
var _this = this
if (this.closeTimmer && this.timmer) { //如果没有连接成功,或者断开连接,直接清除定时器
clearInterval(this.timmer);
}
this.webSocket = new WebSocket(this.wsUrl, [this.user_key])
this.webSocket.onopen = function (evt) { //1: 用来连接 websoket
console.log("Connection open ... binduser");
};
this.webSocket.onmessage = function (evt) { //2: 连接成功后台返回的响应
var data = JSON.parse(evt.data);
var type = data.type
if (type != 'pong') { //监听心跳,用来判断是否短路
_this.handleMsg(type, data.ret)
}
};
this.webSocket.onclose = function (evt) {
console.log("Connection closed. reconnect");
};
/*
状态1: 连接成功
状态3: 连接已关闭或者没有链接成功
*/
this.timmer = setInterval(function () {
if (_this.webSocket.readyState == 1) {
data = { type: "ping" }
_this.webSocket.send(JSON.stringify(data))
}
if (_this.webSocket.readyState == 3) {
_this.closeTimmer = true
_this.connectIm()
}
}, 30000)
},
translateItem(item, index, to) {
var sendMsg = {
type: 'fanyi',
data: {
id: item.id,
to: to,
index: index
}
}
this.webSocket.send(JSON.stringify(sendMsg))
},
closeMainBox(){
if(!this.clickTranslate){
return
}
this.activeFy = ""
this.clickTranslate = false
},
// closeFy(item, index){
// // if (this.activeFy == '') {
// // return
// // }
// // if (this.activeFy > 0 && this.activeFy != "") {
// // // var tmp = JSON.parse(JSON.stringify(this.nowMsg[index]))
// // // tmp.translation_content = ''
// // this.activeFy = ""
// // this.clickTranslate = false
// // // this.$set(this.nowMsg, index, tmp)
// // }
// },
translate(item, index) { //点击翻译
this.activeFy = index
this.clickTranslate = true
},
handleMsg(type, ret) {
switch (type) {
case "fanyi":
var tmp = JSON.parse(JSON.stringify(this.nowMsg[ret.index]))
tmp.translation_content = ret.content
this.$set(this.nowMsg, ret.index, tmp)
break;
case "bindUser": //获取当前聊天人员信息
this.webSocket.send(JSON.stringify({ type: "getUserList", data: {} }))
break;
case 'getUserList'://获取当前人员聊天列表
var that = this
this.kefuList = ret.kefu
this.activeObj = ret.kefu[0] // 当前聊天客服
this.kefuList.forEach(function (item, index) {
item.has_new_msg = false, //是否新信息
item.is_chose = false, //当前是否点击
item.type = 'im_kefu', //当前聊天人员类型
item.content = ""//新信息
if (that.activeObj.user_id == item.user_id) {
that.kefuList[index].is_chose = true
}
})
break;
case "getMessage": //获取当前聊天人员信息
this.is_next = ret.msg.length > 0 ? true : false
if (ret.page == 1) {
this.nowMsg = ret.msg.reverse()
this.setScrollToBottomTime()
} else {
var tmp = ret.msg.reverse()
tmp = tmp.concat(this.nowMsg)
this.nowMsg = tmp
this.$nextTick(() => {
var height = 0
for (let index = 0; index < ret.msg.length; index++) {
const element = this.$refs.chatPage_right_main_ref_for[index];
height += element.clientHeight
}
this.$refs.chatPage_right_main_ref.scrollTop = height
})
}
break;
case "recvMsg":
var that = this
var data = ret.msg
var menuImg = this.$refs.kehuMenuImg
this.kefuList.forEach((item, index) => {
if (item.supply_id == Number(data.to_uid)) {
this.kefuList[index].has_new_msg = true
this.kefuList[index].content = data.content
that.isNextOpen = true
}
})
if (data.to_uid == this.activeObj.supply_id) {
this.nowMsg.push(data)
}
menuImg.setAttribute('src', that.isNextOpen ? '/Public/images/imWeb_ColorKehuMenu.png' : '/Public/images/imWeb_kehuMenu.png')
if(this.userInfo.client == "mobile"){
var params = ret.msg
params.newMessge = true
window.parent.postMessage({
cmd: 'returnMessge',
params:params
}, '*');
}
this.setScrollToBottomTime()
break
case "showLine":
this.on_line = ret.is_online
break;
}
},
setScrollToBottomTime(){
new Promise((reslove)=>{
var id = setTimeout(()=>{
reslove(id)
},55)
}).then(id=>{
this.scrollToBottom()
clearTimeout(id)
})
},
scrollToBottom (){
this.$nextTick(() => { //思路 获取最外层包裹DIV,利用循环获取里面循环的每一个高度, 然后最外层整个盒子的高度等于循环div里面的总高度
var refDom = this.$refs.chatPage_right_main_ref_for //包裹数组循环的div
var refBox = this.$refs.chatPage_right_main_ref //包裹整个div的盒子
var len = 0
if (refDom && refDom.length > 0) {
refDom.forEach((item,index) => {
len += item.clientHeight
})
refBox.scrollTop = len
}
})
},
showLine: function (obj) {
obj.supply_id = obj.user_id
var sendMsg = {
type: 'showline',
data: obj
}
this.webSocket.send(JSON.stringify(sendMsg))
},
getMessage: function (to_obj, page) {
var sendMsg = {
type: 'getMessage',
msg_type: this.userInfo.path == 'sanhuo' ? 2 : 1,//散货2 钻石列表1
data: {
uid: this.userInfo.uid,
to_uid: to_obj.user_id,
to_type: 1,
page: page
},
}
this.webSocket.send(JSON.stringify(sendMsg))
},
getFile(event) {
var that = this
var form = new FormData();
let file = event.target.files[0];
form.append('file', file)
var fileUrl = this.userInfo.client == 'miniapp' ? '/Api_view/Com/uploadImg' : "/public/uploadImg"
axios.post(fileUrl, form).then(res => {
new Promise((reslove, resject) => {
if (res.data.status == 100) {
reslove(res.data.img_path)
} else {
resject(res)
}
}).then(res => {
this.fileResult = res
this.sendMessge('file', true)
})
})
},
sendMessge(str, type = '') {
if(str == 'keydown' && event.keyCode == 13 && this.notedata == ''){
event.preventDefault()
return
}
if (str == 'messge' && this.notedata == '') {
return
}
if (event.keyCode && event.keyCode != 13) {
return
}
var params = {
content_type: 0,
content: type ? this.fileResult : this.notedata, //当前发送的信息
is_upload: type ? 1 : 0, // 1图片,0文本
}
/*
@params{
to_uid, 和谁聊天
type, 与当前聊天人的类型
msg, 当前是文本还是图片
content_type, 发送的内容
}
*/
var sendMsg = {
type: "sendMsg",
data: { to_uid: this.activeObj.user_id, type: this.activeObj.type, msg: params.content, content_type: params.content_type, is_upload: params.is_upload }
};
var data = {
content: params.content,
add_time: this.dateFormat("YYYY-mm-dd HH:MM:SS", new Date()),
is_main: 1,
type: params.content_type,
is_upload: type ? 1 : 0 // 1图片,0文本
}
//发送的消息保存本地
if (this.nowMsg) {
this.nowMsg.push(data)
} else {
this.nowMsg = [data]
}
//发送消息
this.webSocket.send(JSON.stringify(sendMsg))
this.setScrollToBottomTime()
event.target.value = ''
this.notedata = ''
this.$refs.textareaRef.value = ''
},
clickehuList(item, index) {
for (let i in this.kefuList) {
if (Number(i) == index) {
if (this.kefuList[i].is_chose == true) {
this.kefuList[i].has_new_msg = false
this.clickKehu()
return
}
this.kefuList[i].is_chose = true
this.kefuList[i].has_new_msg = false
this.activePage = 1
this.activeObj = this.kefuList[i] // 当前聊天客服
this.clickKehu()
this.setScrollToBottomTime()
} else {
this.kefuList[i].is_chose = false
}
}
},
clickKehu() {
if (this.isNextOpen) {
this.isShowPopUp = true
}
var that = this
var imWebPopupRightList = ''
this.$nextTick(() => { imWebPopupRightList = this.$refs.imWeb_popup_right_list })
if (this.flag) {
var maxCount = 0
var timeId = setInterval(function () {
if (that.isNextOpen) {
that.flag = false
maxCount++
imWebPopupRightList.style.width = maxCount + '%'
if (maxCount == 75) {
that.isNextOpen = !that.isNextOpen
that.flag = !that.flag
clearInterval(timeId)
return
}
} else {
that.flag = false
maxCount = parseInt(imWebPopupRightList.style.width)
--maxCount
imWebPopupRightList.style.width = maxCount + '%'
if (maxCount == 0) {
that.isNextOpen = true
that.flag = true
imWebPopupRightList.removeAttribute("class")
that.isShowPopUp = false
clearInterval(timeId)
return
}
}
}, 5)
}
},
dateFormat(fmt, date) {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
}
},
})
</script>
</html>