vue 環信內建
(标記)
檢視官方文檔 下載下傳的vue demo 需求不合适自己的 ,是以改吧了改吧
需要寫一個單聊的功能 不需要加好友 隻是單純的聊天
因為公司沒買增值服務 太費錢了 是以隻做個本地存儲 退出就删 因為store一重新整理就沒了 是以就存浏覽器了
-
安裝 easemob-websdk
npm install easemob-websdk --save
-
安裝 moment
npm install moment --save
下載下傳案例
- 将案例的 utils 檔案複制到自己的 src下 将WebIMConfig中的appkey改成公司申請的
- 修改WebIM中代碼
import Vue from 'vue';
import store from '../store'
import config from "./WebIMConfig";
import websdk from "easemob-websdk";
import { Message } from "element-ui";
// 初始化IM SDK
var WebIM = {};
WebIM = window.WebIM = websdk;
WebIM.config = config;
WebIM.conn = new WebIM.connection({ //建立連接配接
appKey: WebIM.config.appkey,
isHttpDNS: WebIM.config.isHttpDNS,
isMultiLoginSessions: WebIM.config.isMultiLoginSessions,
https: WebIM.config.https,
url: WebIM.config.xmppURL,
apiUrl: WebIM.config.apiURL,
isAutoLogin: true,
heartBeatWait: WebIM.config.heartBeatWait,
autoReconnectNumMax: WebIM.config.autoReconnectNumMax,
autoReconnectInterval: WebIM.config.autoReconnectInterval,
isStropheLog: WebIM.config.isStropheLog,
delivery: WebIM.config.delivery
});
if (!WebIM.conn.apiUrl) {
WebIM.conn.apiUrl = WebIM.config.apiURL;
}
// 注冊監聽回調
WebIM.conn.listen({
onOpened: function(message) { // 連接配接成功回調
console.log('環信登入成功')
},
onClosed: function(message) { //連接配接關閉回調
Vue.$router.push({ path: "/Login" });
}, // 連接配接關閉回調
onTextMessage: function(message) { //收到文本消息
console.log(message)
const { from, to, type } = message;
const chatId = type !== "chat" ? to : from;
store.commit("updateMsgList", {
headPic: message.ext.headPic,
nickName: message.ext.nickName,
chatId: chatId,
msg: message.data,
bySelf: false,
from: message.from,
mid: message.id
});
store.commit("updateUserList", {
headPic: message.ext.headPic,
nickName: message.ext.nickName,
chatId: chatId,
msg: message.data,
bySelf: false,
from: message.from,
mid: message.id
});
type === 'chat' && ack(message);
if (WebIM && WebIM.call && message && message.ext && message.ext.msg_extension) {
var msgExtension = message.ext.msg_extension && JSON.parse(message.ext.msg_extension);
var options = {
confrId: message.ext.conferenceId,
password: message.ext.password || "",
gid: msgExtension.group_id,
inviter: msgExtension.inviter
};
WebIM.call.listener.onInvite(message.from, options);
}
},
onEmojiMessage: function(message) { // 收到表情消息
console.log("onEmojiMessage", message);
},
onPictureMessage: function(message) { //收到圖檔消息
console.log("onPictureMessage", message);
const { from, to, type } = message;
const chatId = type !== "chat" ? to : from;
store.commit("updateMsgList", {
nickName: message.ext.nickName,
headPic: message.ext.headPic,
chatId: chatId,
msg: message.url,
bySelf: false,
type: "img",
mid: message.id,
from: message.from
});
store.commit("updateUserList", {
nickName: message.ext.nickName,
headPic: message.ext.headPic,
chatId: chatId,
msg: message.url,
bySelf: false,
type: "img",
mid: message.id,
from: message.from
});
type === 'chat' && ack(message);
},
onCmdMessage: function(message) {
console.log("onCmdMessage", message);
},
onAudioMessage: function(message) { // 收到音頻消息
console.log("onAudioMessage", message);
},
onLocationMessage: function(message) { // 收到位置消息
console.log("onLocationMessage", message);
},
onFileMessage: function(message) { // 收到檔案消息
console.log("onFileMessage", message);
const { from, to, type } = message;
const chatId = type !== "chat" ? to : from;
store.commit("updateMsgList", {
headPic: message.ext.headPic,
nickName: message.ext.nickName,
chatId: chatId,
msg: message.url,
bySelf: false,
type: "file",
filename: message.filename,
file_length: message.file_length,
from: message.from
});
store.commit("updateUserList", {
headPic: message.ext.headPic,
nickName: message.ext.nickName,
chatId: chatId,
msg: message.url,
bySelf: false,
type: "file",
filename: message.filename,
file_length: message.file_length,
from: message.from
});
type === 'chat' && ack(message);
},
onVideoMessage: function(message) { // 收到視訊消息
console.log("onVideoMessage", message);
},
onPresence: function(message) {
console.log("onPresence", message);
}, // 處理“廣播”或“釋出-訂閱”消息,如聯系人訂閱請求、處理群組、聊天室被踢解散等消息
onRoster: function(message) {
console.log("onRoster", message);
}, // 處理好友申請
onInviteMessage: function(message) {
console.log("onInviteMessage", message);
}, // 處理群組邀請
onOnline: function() {
console.log("onOnline 網絡已連接配接");
}, // 本機網絡連接配接成功
onOffline: function() {
console.log("onOffline 網絡已斷開");
}, // 本機網絡掉線
onError: function(message) {
console.log(message)
}, // 失敗回調
onRecallMessage: message => {
console.log("撤回消息", message);
},
onBlacklistUpdate: function(list) { // 黑名單變動
// 查詢黑名單,将好友拉黑,将好友從黑名單移除都會回調這個函數,list則是黑名單現有的所有好友資訊
// 更新好友黑名單
},
onReceivedMessage: function(message) {
console.log("onReceivedMessage", message);
}, // 收到消息送達伺服器回執
onDeliveredMessage: function(message) {}, // 收到消息送達用戶端回執
onReadMessage: function(message) {
console.log("onReadMessage", message);
// store.commit("updateMessageStatus", message);
}, // 收到消息已讀回執
onCreateGroup: function(message) {}, // 建立群組成功回執(需調用createGroupNew)
onMutedMessage: function(message) {} // 如果使用者在A群組被禁言,在A群發消息會走這個回調并且消息不會傳遞給群其它成員
});
export default WebIM;
- main.js 中
import WebIM from './utils/WebIM';
new Vue({
el: '#app',
router,
store,
WebIM,
components: { App },
template: '<App/>'
})
- store 添加 login.js
import { Message } from "element-ui";
const Login = {
state: {
// username: ""
imusername: "" //登入使用者賬号
},
mutations: {
setUserName(state, username) {
state.imusername = username;
},
},
actions: {
onLogin: function(context, payload) {
context.commit("setUserName", payload.username);
var options = {
apiUrl: WebIM.config.apiURL,
user: payload.username,
pwd: payload.password,
appKey: WebIM.config.appkey
};
WebIM.conn.open(options);
localStorage.setItem("imuserInfo", JSON.stringify({ userId: payload.username, password: payload.password }));
},
onLogout: function(context) {
context.commit("setUserName", "");
// localStorage.setItem("userInfo", "");
},
},
getters: {
}
};
export default Login;
-
store 添加 chat.js
有些沒用的 也沒删
import Vue from 'vue';
import WebIM from "../utils/WebIM";
// import WebIM from "../utils/WebIM";
// TODO 處理頁面重新整理無法擷取到音頻url
const res = function(response) {
let objectUrl = WebIM.utils.parseDownloadResponse.call(WebIM.conn, response);
return objectUrl; // 'blob:http://localhost:8080/536070e2-b3a0-444a-b1cc-f0723cf95588'
};
function test(url, func) {
let options = {
url: url,
headers: {
Accept: "audio/mp3"
},
onFileDownloadComplete: func,
onFileDownloadError: function() {
console.log("音頻下載下傳失敗");
}
};
WebIM.utils.download.call(WebIM.conn, options);
}
const Chat = {
state: {
userList: {},
msgList: {},
currentMsgs: []
},
mutations: {
updateUserList(state, payload) {
console.log(payload)
const {
chatId,
} = payload;
var immsgList = JSON.parse(localStorage.getItem("immsgList"));
var imuserList = JSON.parse(localStorage.getItem("imuserList"));
if (imuserList !== null && imuserList !== '') { //登入狀态
state.msgList = immsgList
state.userList = imuserList
if (!state.userList[chatId]) {
state.userList[chatId] = {
name: chatId,
nickName: payload.nickName,
headPic: payload.headPic,
subscription: "to"
}
} else {
state.userList[chatId] = {
name: chatId,
nickName: payload.nickName,
headPic: payload.headPic,
subscription: "to"
}
state.userList[chatId] = state.userList[chatId].sort((a, b) => {
return b.time - a.time;
});
}
state.userList = Object.assign({}, state.userList);
localStorage.setItem("imuserList", JSON.stringify(state.userList))
} else {
if (!state.userList[chatId]) {
state.userList[chatId] = {
name: chatId,
nickName: payload.nickName,
headPic: payload.headPic,
subscription: "to"
}
} else {
state.userList[chatId] = {
name: chatId,
nickName: payload.nickName,
headPic: payload.headPic,
subscription: "to"
}
state.userList[chatId] = state.userList[chatId].sort((a, b) => {
return a.time - b.time;
});
console.log(state.userList)
}
state.userList = Object.assign({}, state.userList);
localStorage.setItem("imuserList", JSON.stringify(state.userList))
}
},
updateMsgList(state, payload) { // 消息清單
const {
chatId,
msg,
bySelf,
type,
id
} = payload;
var immsgList = JSON.parse(localStorage.getItem("immsgList"));
if (immsgList !== null && immsgList !== '') { //登入狀态
state.msgList = immsgList
if (!state.msgList[chatId]) {
state.msgList[chatId] = [{
msg,
bySelf,
type: type || "",
mid: id,
headPic: payload.headPic,
nickName: payload.nickName,
...payload
}];
} else {
state.msgList[chatId].push({
msg,
bySelf,
type: type || "",
headPic: payload.headPic,
nickName: payload.nickName,
mid: id,
...payload
});
state.msgList[chatId] = state.msgList[chatId].sort((a, b) => {
return a.time - b.time;
});
}
state.msgList = Object.assign({}, state.msgList);
localStorage.setItem("immsgList", JSON.stringify(state.msgList))
} else { //退出了 在登入
if (!state.msgList[chatId]) {
state.msgList[chatId] = [{
msg,
bySelf,
type: type || "",
headPic: payload.headPic,
nickName: payload.nickName,
mid: id,
...payload
}];
} else {
state.msgList[chatId].push({
msg,
bySelf,
type: type || "",
mid: id,
headPic: payload.headPic,
nickName: payload.nickName,
...payload
});
state.msgList[chatId] = state.msgList[chatId].sort((a, b) => {
return a.time - b.time;
});
}
state.msgList = Object.assign({}, state.msgList);
localStorage.setItem("immsgList", JSON.stringify(state.msgList))
}
},
updateCurrentMsgList(state, messages) {
state.currentMsgs = messages;
},
updateMessageMid(state, message) {
const {
id,
mid
} = message;
const {
name,
params
} = Vue.$route;
state.currentMsgs.forEach((item) => {
if (item.mid == id) {
item.mid = mid
}
})
Object.keys(state.msgList[name]).forEach((user) => {
if (state.msgList[name][user].length) {
state.msgList[name][user].forEach((msg) => {
if (msg.mid == id) {
msg.mid = mid;
}
});
}
});
},
updateMessageStatus(state, message) {
const {
id,
mid,
action,
readUser
} = message;
const {
name,
params
} = Vue.$route;
Object.keys(state.msgList[name]).forEach((user) => {
// console.log(state.msgList[name][user]);
if (action == "oneUserReadMsgs") {
if (state.msgList[name][readUser]) {
state.msgList[name][readUser].forEach((msg) => {
if (msg.status != "recall") {
msg.status = "read";
}
});
}
} else if (state.msgList[name][user].length) {
state.msgList[name][user].forEach((msg) => {
if (action === "readMsgs" && !msg.bySelf) {
if (msg.status != "recall") {
msg.status = "read";
}
} else if (msg.mid == id || msg.mid == mid) {
msg.status = message.status;
if (message.msg) {
msg.msg = message.msg;
}
}
});
}
});
},
},
actions: {
onGetContactUserList: function(context, payload) {
try {
WebIM.conn.getRoster({ //查詢好友清單
success: function(roster) {
console.log("roster", roster);
const userList = roster.filter(user => ["both", "to"].includes(user.subscription));
context.commit("updateUserList", {
userList,
type: "contactUserList",
black: payload
});
}
});
} catch (e) {
console.log("error", e);
}
},
// 擷取目前聊天對象的記錄 @payload: {key, type}
onGetCurrentChatObjMsg: function(context, payload) {
const {
id,
type
} = payload;
context.commit("updateCurrentMsgList", context.state.msgList[type][id]);
},
onSendText: function(context, payload) { //發送文本資訊
const {
nickName,
headPic,
chatId,
message
} = payload;
const id = WebIM.conn.getUniqueId();
const time = +new Date();
const msgObj = new WebIM.message("txt", id);
msgObj.set({
msg: message,
ext: {
'headPic': headPic,
'nickName': nickName,
},
to: chatId,
success: function() {
console.log('fdsf')
context.commit("updateMsgList", {
headPic: headPic,
nickName: nickName,
chatId: chatId,
msg: message,
bySelf: true,
time: time,
mid: id,
});
context.commit("updateUserList", {
headPic: headPic,
nickName: nickName,
chatId: chatId,
msg: message,
bySelf: true,
time: time,
mid: id,
});
},
fail: function(e) {
console.log("Send private text error", e);
}
});
WebIM.conn.send(msgObj.body);
},
sendImgMessage: function(context, payload) { //發送圖檔資訊
const {
nickName,
headPic,
chatId,
file,
callback
} = payload;
const id = WebIM.conn.getUniqueId();
const msgObj = new WebIM.message("img", id);
msgObj.set({
apiUrl: WebIM.config.apiURL,
file: file,
ext: {
'headPic': headPic,
'nickName': nickName,
},
to: chatId,
onFileUploadError: function(error) {
console.log("圖檔上傳失敗", error);
callback();
},
onFileUploadComplete: function(data) {
let url = data.uri + "/" + data.entities[0].uuid;
context.commit("updateMsgList", {
headPic: headPic,
msg: url,
nickName: nickName,
chatId: chatId,
bySelf: true,
type: "img",
time: data.timestamp,
mid: id,
});
context.commit("updateUserList", {
headPic: headPic,
msg: url,
nickName: nickName,
chatId: chatId,
bySelf: true,
type: "img",
time: data.timestamp,
mid: id,
});
callback();
},
success: function() {
console.log("圖檔發送成功");
}
});
WebIM.conn.send(msgObj.body);
},
sendFileMessage: function(context, payload) {
const {
nickName,
headPic,
chatId,
file,
callback
} = payload;
const id = WebIM.conn.getUniqueId();
const msgObj = new WebIM.message("file", id);
msgObj.set({
apiUrl: WebIM.config.apiURL,
file: file,
ext: {
'headPic': headPic,
'nickName': nickName,
},
ext: {
file_length: file.data.size
},
to: 19956,
onFileUploadError: function(error) {
console.log("檔案上傳失敗", error);
callback();
},
onFileUploadComplete: function(data) {
let url = data.uri + "/" + data.entities[0].uuid;
context.commit("updateMsgList", {
headPic: headPic,
msg: url,
nickName: nickName,
chatId: chatId,
bySelf: true,
type: "file",
filename: file.data.name,
file_length: file.data.size,
time: data.timestamp,
mid: id,
// status: "sending"
});
context.commit("updateUserList", {
headPic: headPic,
msg: url,
nickName: nickName,
chatId: chatId,
bySelf: true,
type: "file",
filename: file.data.name,
file_length: file.data.size,
time: data.timestamp,
mid: id,
// status: "sending"
});
callback();
},
success: function() {
console.log("檔案發送成功");
}
});
WebIM.conn.send(msgObj.body);
},
getHistoryMessage: function(context, payload) {
const options = {
queue: payload.name,
isGroup: payload.isGroup,
count: 10, // 每次擷取消息條數
success: function(msgs) {
try {
payload.success && payload.success(msgs);
if (msgs.length) {
const userInfo = JSON.parse(localStorage.getItem("userInfo"));
const userId = userInfo && userInfo.userId;
msgs.forEach((item) => {
let time = Number(item.time);
let msg = {};
const bySelf = item.from == userId;
if (!item.filename) {
msg = {
chatType: payload.isGroup ? "group" : "contact",
chatId: bySelf ? item.to : item.from,
msg: item.data,
bySelf: bySelf,
time: time,
mid: item.id,
status: "read"
};
if (payload.isGroup) {
msg.chatId = item.to;
} else {
msg.chatId = bySelf ? item.to : item.from;
}
} else if (!item.ext.file_length && item.filename !== "audio" && item.filename.substring(item.filename.length - 3) !== "mp4") { // 為圖檔的情況
msg = {
msg: item.url,
chatType: payload.isGroup ? "group" : "contact",
chatId: bySelf ? item.to : item.from,
bySelf: bySelf,
type: "img",
time: time,
mid: item.id,
status: "read"
};
if (payload.isGroup) {
msg.chatId = item.to;
} else {
msg.chatId = bySelf ? item.to : item.from;
}
} else if (item.filename === "audio") {
msg = {
msg: item.url,
chatType: payload.isGroup ? "group" : "contact",
chatId: bySelf ? item.to : item.from,
bySelf: bySelf,
type: "audio"
};
if (payload.isGroup) {
msg.chatId = item.to;
} else {
msg.chatId = bySelf ? item.to : item.from;
}
} else if (item.filename.substring(item.filename.length - 3) === "mp4") {
msg = {
msg: item.url,
chatType: payload.isGroup ? "group" : "contact",
chatId: bySelf ? item.to : item.from,
bySelf: bySelf,
type: "video"
};
if (payload.isGroup) {
msg.chatId = item.to;
} else {
msg.chatId = bySelf ? item.to : item.from;
}
} else {
msg = {
msg: item.url,
chatType: payload.isGroup ? "group" : "contact",
chatId: bySelf ? item.to : item.from,
bySelf: bySelf,
type: "file",
filename: item.filename,
file_length: item.file_length,
time: time,
mid: item.id,
status: "read"
};
if (payload.isGroup) {
msg.chatId = item.to;
} else {
msg.chatId = bySelf ? item.to : item.from;
}
}
msg.isHistory = true;
context.commit("updateMsgList", msg);
context.commit("updateUserList", msg);
});
context.commit("updateMessageStatus", {
action: "readMsgs"
});
}
} catch (e) {
console.log("error", e);
}
},
fail: function() {}
};
WebIM.conn.fetchHistoryMessages(options);
},
recallMessage: function(context, payload) {
const {
chatType,
mid
} = payload.message;
const to = payload.to;
const me = this;
const chatTypeObj = {
contact: "chat",
group: "groupchat",
chatroom: "chatroom"
};
const option = {
mid,
to,
type: chatTypeObj[chatType],
success: function() {
payload.message.status = "recall";
payload.message.msg = "消息已撤回";
Vue.$store.commit("updateMessageStatus", payload.message);
},
fail: function() {
// me.$message('消息撤回失敗');
},
};
WebIM.conn.recallMessage(option);
}
},
getters: {
onGetContactUserList(state) {
return state.userList.contactUserList;
},
onGetCurrentChatObjMsg(state) {
return state.currentMsgs;
},
fetchHistoryMessages(state) {
return state.currentMsgs;
}
}
};
export default Chat;
-
複制 chartEmoji upLoadFile upLoadImage 檔案到 compnents
upLoadGile
<template>
<label for="uploadFile">
<i class="el-icon-folder" color="rgba(0, 0, 0, 0.65)" />
<input id="uploadFile" type="file" accept="video/mp4,audio/mp4" capture="camcorder" class="hide" ref="imgDom" @change="fileChange" />
</label>
</template>
<script>
import WebIM from "../../utils/WebIM";
import Config from "../../config/index";
import { mapActions } from "vuex";
export default {
data(){
return {
file: null
};
},
methods: {
...mapActions(["sendFileMessage"]),
// TODO 目前username、及type不是從pams裡取
fileChange(e){
let file = WebIM.utils.getFileUrl(e.target);
if(!file.filename){
this.$refs.imgDom.value = null;
return false;
}
let obj = {
chatId: this.chatId.name, // TODO 這裡在群裡面應該取的是ID,後期跟進
file: file,
headPic:this.chatId.url,
nickName:this.chatId.nickname,
callback: () => {
this.$refs.imgDom.value = null;
}
};
this.sendFileMessage(obj);
}
},
props: [
"type", // 聊天類型 contact, group, chatroom
"chatId" // 選中的聊天對象
],
created(){
}
};
</script>
<style scoped>
.hide {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
filter: alpha(opacity=0);
opacity: 0;
cursor: inherit;
display: none;
}
i{
font-size:20px;
margin-left: 8px;
cursor: pointer
}
</style>
upLoadImage中
<template>
<label for="uploadImage" >
<i class="el-icon-picture-outline" color="rgba(0, 0, 0, 0.65)" />
<input id="uploadImage" type="file" accept="image/png, image/jpeg, image/jpg" class="hide" ref="imgDom" @change="pictureChange($event)" />
</label>
</template>
<script>
import WebIM from "../../utils/WebIM";
import Config from "../../config/index";
import { mapActions } from "vuex";
export default {
data() {
return {
image: null
};
},
methods: {
...mapActions(["sendImgMessage"]),
// TODO 目前username、及type不是從pams裡取
pictureChange(e) {
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
alert("圖檔類型必須是.jpeg,jpg,png中的一種");
return false;
}
let file = WebIM.utils.getFileUrl(e.target);
if (!file.filename) {
this.$refs.imgDom.value = null;
return false;
}
let obj = {
chatId: this.chatId.name, //TODO 這裡在群裡面應該取的是ID,後期跟進
file: file,
nickName:this.chatId.nickname,
headPic:this.chatId.url,
callback: () => {
this.$refs.imgDom.value = null;
}
};
this.sendImgMessage(obj);
},
},
props: [
"type", // 聊天類型 contact, group, chatroom
"chatId" // 選中的聊天對象
],
created(){
}
};
</script>
<style scoped>
.hide {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
filter: alpha(opacity=0);
opacity: 0;
cursor: inherit;
display: none;
}
i{
font-size:20px;
margin-left: 8px;
cursor: pointer
}
</style>
- store index.js中引入
import Login from "./login";
import Chat from "./chat";
const store = new Vuex.Store({
modules: {
//環信測試
Login: Login,
chat: Chat,
//環信測試
}
});
清除存儲
mutations: {
clearToken(state) {
//環信測試
localStorage.removeItem('imuserInfo'); // 登入環信使用者
localStorage.removeItem('immsgList'); //資訊清單
localStorage.removeItem('imcurrenu'); //目前聊天對象
localStorage.removeItem('imuserList'); //聊天對象清單
Chat.state.msgList = {}
Chat.state.userList = {}
//環信測試
},
}
- 添加頁面 webuserlist.vue 使用者清單
<template>
<div class="" style="width:100%;padding:30px 100px;">
<ul>
<li v-for="item in artistlist" :key="item.name" style="padding:20px 0;">
<img :src="item.url" alt="" style="display:inline-block;width:30px;height:30px;border-radius:50%;">
<span>{{item.name}}</span>
<span style="display:inline-block;width:60px;font-size:12px;height:30px;line-height:30px;text-align:center;background:green;color:#fff;cursor: pointer;" @click="tochat(item)">私信</span>
</li>
</ul>
<div>會話清單</div>
<ul>
</ul>
</div>
</template>
<script>
// 點選私信進入私信聊天
export default {
data () {
return {
artistlist:[
{
formu: localStorage.getItem("imuserInfo") &&
JSON.parse(localStorage.getItem("imuserInfo")).userId,//目前使用者
nickname:'小明',
name:'使用者登入id',
subscription:'to',
url:''
},
],
userName:
localStorage.getItem("imuserInfo") &&
JSON.parse(localStorage.getItem("imuserInfo")).userId,
}
},
created(){
},
methods:{
tochat:function(val){
//加入好友聊天頁面
if(this.userName!==val.name){
// 是否有聊天清單
localStorage.setItem("imcurrenu", JSON.stringify(val))
this.$router.push({path:'/webIm',query:{imname:val.name}})
}
},
}
}
</script>
<style>
p{
cursor: pointer;
}
</style>
- 添加頁面 webimlist.vue 會話清單
<template>
<div id="webImPage" :style="{ height: clientHeight - 64 + 'px' }">
<div class="messbox">
<el-menu style="width: 100%; border-right: 0;" mode="vertical">
<div v-if="haslist" style="text-align:left;color:#666;font-size:20px;">無資料</div>
<div v-if="!haslist">
<el-menu-item
style="height: 80px; position: relative; textAlign: left; borderBottom: 1px solid #eee; margin: 0"
v-for="(item) in userList" :key="getKey(item)"
@click="tochat(item)"
>
<span class="custom-title">{{ item.nickName }}</span>
<div class="icon-style" v-if="getUnreadNum(item) != 0">
<span class="unreadNum">{{ getUnreadNum(item) }}</span>
</div>
<span class="time-style" style="float:right">{{
getLastMsg(item).msgTime
}}</span>
<div v-html="getLastMsg(item).lastMsg"></div>
</el-menu-item>
</div>
</el-menu>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import moment from "moment";
import emoji from "../config/emoji";
export default {
data() {
return {
type:'contact',
haslist:'',
clientHeight:'',
userName:
localStorage.getItem("imuserInfo") &&
JSON.parse(localStorage.getItem("imuserInfo")).userId,
};
},
computed: {
...mapGetters({
msgList: "onGetCurrentChatObjMsg"
}),
userList() {
var infol = JSON.parse(localStorage.getItem("imuserList"));
if (infol !== null && infol !== "") {
this.$store.state.chat.userList = infol;
this.haslist=false
console.log(this.$store.state.chat.userList)
return this.$store.state.chat.userList;
} else {
this.haslist=true
console.log(this.$store.state.chat.userList)
return this.$store.state.chat.userList;
}
},
chatList() {
var infol = JSON.parse(localStorage.getItem("immsgList"));
if (infol !== null && infol !== "") {
this.$store.state.chat.msgList = infol;
return this.$store.state.chat.msgList;
} else {
return this.$store.state.chat.msgList;
}
},
},
methods: {
tochat:function(val){
//加入好友聊天頁面
// 是否有聊天清單
var data={
formu: localStorage.getItem("imuserInfo") &&
JSON.parse(localStorage.getItem("imuserInfo")).userId,//目前使用者
nickname:val.nickName,
name:val.name,
subscription:'to',
url:val.headPic
}
localStorage.setItem("imcurrenu", JSON.stringify(data))
this.$router.push({path:'/webIm',query:{imname:val.name}})
},
...mapActions([
"onGetCurrentChatObjMsg"
]),
getUnreadNum(item) {
const chatList = this.chatList[item.name];
let userId = "";
userId = item.name;
const currentMsgs = chatList || [];
let unReadNum = 0;
currentMsgs.forEach(msg => {
console.log(msg)
// if (msg.status !== "read" && msg.status !== "recall" && !msg.bySelf) {
// unReadNum++;
// }
});
return unReadNum;
},
getLastMsg(item) {
const chatList = this.chatList[item.name];
let userId = "";
userId = item.name;
console.log(chatList)
const currentMsgs = chatList || [];
let lastMsg = "";
console.log(currentMsgs[currentMsgs.length - 1])
let lastType =
currentMsgs.length && currentMsgs[currentMsgs.length - 1].type;
if (currentMsgs.length>0) {
if (lastType === "img") {
lastMsg = "[image]";
} else if (lastType === "file") {
lastMsg = currentMsgs[currentMsgs.length - 1].filename;
} else if (lastType === "audio") {
lastMsg = "[audio]";
} else if (lastType === "vidio") {
lastMsg = "[vidio]";
} else {
lastMsg = currentMsgs[currentMsgs.length - 1].msg;
}
}
let rnTxt = [];
let match = null;
const regex = /(\[.*?\])/g;
let start = 0;
let index = 0;
while ((match = regex.exec(lastMsg))) {
index = match.index;
if (index > start) {
rnTxt.push(lastMsg.substring(start, index));
}
if (match[1] in emoji.obj) {
const v = emoji.obj[match[1]];
rnTxt.push(this.customEmoji(v));
} else {
rnTxt.push(match[1]);
}
start = index + match[1].length;
}
rnTxt.push(lastMsg.substring(start, lastMsg.length));
rnTxt = rnTxt.toString().replace(/,/g, "");
lastMsg= rnTxt
const msgTime = currentMsgs.length
? this.renderTime(currentMsgs[currentMsgs.length - 1].time)
: "";
return {
lastMsg,
msgTime
};
},
customEmoji(value) {
return `<img src="../../../static/faces/${value}" style="width:20px"/>`;
},
getKey(item) {
let key = "";
key = item.name;
},
// TODO 可以抽離到utils
renderTime(time) {
const nowStr = new Date();
const localStr = time ? new Date(time) : nowStr;
const localMoment = moment(localStr);
const localFormat = localMoment.format("MM-DD hh:mm A");
return localFormat;
},
getHeight: function () {
this.clientHeight = `${document.documentElement.clientHeight}`;
},
},
created(){
this.getHeight()
console.log('fdsf')
},
};
</script>
<style scoped lang="less">
* {
margin: 0;
padding: 0;
}
input[name="sendmess"] {
height: 100%;
border: none;
}
#webImPage {
// height:200px;
width: 100%;
height: 100%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #fff;
.messbox {
width: 1152px;
height: 100%;
margin: 0 auto;
}
}
</style>
- 添加頁面 webIM.vue 聊天界面
<template>
<div id="webImPage" :style="{ height: clientHeight - 64 + 'px' }">
<div class="messbox">
<div class="messagebox-header">
<span style="color:red;" >本尊{{ userName }}</span>
<span>其他人{{ hxiteminfo.nickname }}</span>
</div>
<div class="messagebox-content" ref="msgContent">
<div
v-for="(item, i) in chatList"
:key="i"
class="message-group"
:style="{ float: item.bySelf ? 'right' : 'left' }"
>
<h4 style="text-align: left;margin:0">{{ item.from }}</h4>
<!-- 撤回消息 -->
<!-- <div v-if="item.status == 'recall'" class="recallMsg">{{item.msg}}</div>
<div v-if="item.status == 'recall'" class="recallMsg">{{renderTime(item.time)}}</div> -->
<!-- 撤回消息 end -->
<div :style="{ float: item.bySelf ? 'right' : 'left' }">
<span style="user-select: none">
<img
:key="item.id"
:src="item.msg ? item.msg : ''"
v-if="item.type === 'img'"
class="img-style"
/>
<!-- 檔案card -->
<div
v-else-if="item.type === 'file'"
class="file-style"
:style="{ float: item.bySelf ? 'right' : 'left' }"
>
<el-card :body-style="{ padding: '0px' }">
<div style="padding: 14px;">
<h2>檔案</h2>
<span>
<h3>{{ item.filename }}</h3>
</span>
<div class="bottom clearfix">
<span>{{ readablizeBytes(item.file_length) }}</span>
<a :href="item.msg" :download="item.filename">點選下載下傳</a>
</div>
</div>
</el-card>
</div>
<!-- 音頻消息 -->
<div
v-else-if="item.type === 'audio'"
:style="{ float: item.bySelf ? 'right' : 'left' }"
>
<audio :src="item.msg" controls></audio>
</div>
<!-- 視訊消息 -->
<div v-else-if="item.type === 'video'">
<video :src="item.msg" width="100%" controls></video>
</div>
<!-- 聊天消息 -->
<p
v-else
v-html="renderTxt(item.msg)"
:class="{ byself: item.bySelf }"
></p>
</span>
</div>
</div>
</div>
<div class="messagebox-footer">
<div class="footer-icon">
<!-- 表情元件 -->
<ChatEmoji v-on:selectEmoji="selectEmoji" :inpMessage="message" />
<!-- 上傳圖檔元件 -->
<UpLoadImage :type="this.type" :chatId="hxiteminfo" v-if="showico" />
<!-- 上傳檔案元件 -->
<!-- <UpLoadFile :type="this.type" :chatId="hxiteminfo" v-if="showico" /> -->
</div>
<div class="fotter-send">
<el-input
v-model="message"
type="textarea"
@keyup.enter.native="onSendTextMsg"
equired
name="sendmess"
placeholder="消息"
class="sengTxt"
style="resize:none"
ref="txtDom"
/>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import ChatEmoji from "../components/chatEmoji/index.vue";
import UpLoadImage from "../components/upLoadImage/index.vue";
import UpLoadFile from "../components/upLoadFile/index.vue";
import WebIM from "../utils/WebIM";
import moment from "moment";
import emoji from "../config/emoji";
export default {
components: {
ChatEmoji,
UpLoadImage,
UpLoadFile
},
data() {
return {
type: "contact",
activeKey: "contact",
showModal: false,
activedKey: {
contact: {
// name: "lmy999",
// subscription: "both",
}
},
message: "",
clientHeight: "",
userName:
localStorage.getItem("imuserInfo") &&
JSON.parse(localStorage.getItem("imuserInfo")).userId,
hxiteminfo: {},
showico: false,
list: ""
};
},
created() {
this.getHeight();
if (this.$route.query.imname) {
if (
JSON.parse(localStorage.getItem("imcurrenu")).formu === this.userName
) {
this.hxiteminfo = JSON.parse(localStorage.getItem("imcurrenu"));
console.log(this.hxiteminfo)
this.showico = true;
}
}
},
computed: {
// ...mapGetters({
// contact: "onGetContactUserList",
// msgList: "onGetCurrentChatObjMsg"
// }),
userList() {
//擷取聊過天的對象清單集合
return this.$store.state.chat.userList
},
chatList() {
//擷取聊天記錄
var infol = JSON.parse(localStorage.getItem("immsgList"));
if (infol !== null && infol !== "") {
this.$store.state.chat.msgList = infol;
return this.$store.state.chat.msgList[this.hxiteminfo.name];
} else {
return this.$store.state.chat.msgList[this.hxiteminfo.name];
}
}
},
methods: {
getKey(item, type) {
let key = "";
switch (type) {
case "contact":
key = item.name;
break;
case "group":
key = item.groupid;
break;
case "chatroom":
key = item.id;
break;
default:
break;
}
return key;
},
...mapActions([
"onSendText", //發送資訊
// "onGetCurrentChatObjMsg", //擷取資訊清單
"onGetContactUserList", //擷取聊過天的對象清單集合
"getHistoryMessage" //擷取曆史記錄
]),
selectEmoji(v) {
//添加表情
this.$data.message = v;
this.$refs.txtDom.focus(); //給輸入框焦點
},
getHeight: function() {
this.clientHeight = `${document.documentElement.clientHeight}`;
},
onSendTextMsg() {
if (this.$data.message == "" || this.$data.message == "\n") {
this.$data.message = "";
return;
}
console.log({
headPic: this.hxiteminfo.url,
nickName: this.hxiteminfo.nickname,
chatId: this.hxiteminfo.name,
message: this.$data.message
})
this.onSendText({
headPic: this.hxiteminfo.url,
nickName: this.hxiteminfo.nickname,
chatId: this.hxiteminfo.name,
message: this.$data.message
});
this.$data.message = "";
},
// TODO 可以抽離到utils
renderTime(time) {
const nowStr = new Date();
const localStr = time ? new Date(time) : nowStr;
const localMoment = moment(localStr);
const localFormat = localMoment.format("MM-DD hh:mm A");
return localFormat;
},
readablizeBytes(value) {
let s = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
let e = Math.floor(Math.log(value) / Math.log(1024));
return (value / Math.pow(1024, Math.floor(e))).toFixed(2) + " " + s[e];
},
renderTxt: function(txt) {
let rnTxt = [];
let match = null;
const regex = /(\[.*?\])/g;
let start = 0;
let index = 0;
while ((match = regex.exec(txt))) {
index = match.index;
if (index > start) {
rnTxt.push(txt.substring(start, index));
}
if (match[1] in emoji.obj) {
const v = emoji.obj[match[1]];
rnTxt.push(this.customEmoji(v));
} else {
rnTxt.push(match[1]);
}
start = index + match[1].length;
}
rnTxt.push(txt.substring(start, txt.length));
return rnTxt.toString().replace(/,/g, "");
},
customEmoji(value) {
return `<img src="../../../static/faces/${value}" style="width:20px;display:inline-block;"/>`;
}
}
};
</script>
<style lang="less">
@import "../assets/css/webImPage.less";
</style>
- static引入 faces檔案