Browse Source

将私聊和群聊整合成一个组件

master
xie.bx 3 years ago
parent
commit
9feddf33ab
  1. 1
      im-ui/src/api/emotion.js
  2. 218
      im-ui/src/components/chat/ChatBox.vue
  3. 251
      im-ui/src/components/chat/ChatPrivate.vue
  4. 8
      im-ui/src/store/chatStore.js
  5. 147
      im-ui/src/view/Chat.vue
  6. 2
      im-ui/src/view/Friend.vue

1
im-ui/src/api/emotion.js

@ -2,7 +2,6 @@ const emoTextList = ['微笑', '撇嘴', '色', '发呆', '得意', '流泪', '
let transform = (content) => {
console.log(content)
return content.replace(/\#[\u4E00-\u9FA5]{1,3}\;/gi, textToImg);
}

218
im-ui/src/components/chat/ChatGroup.vue → im-ui/src/components/chat/ChatBox.vue

@ -2,7 +2,7 @@
<el-container class="r-chat-box">
<el-header height="60px">
<span>{{title}}</span>
<span title="群聊信息" class="btn-side el-icon-more" @click="showSide=!showSide"></span>
<span title="群聊信息" v-show="this.chat.type=='GROUP'" class="btn-side el-icon-more" @click="showSide=!showSide"></span>
</el-header>
<el-container>
<el-container class="content-box">
@ -54,7 +54,7 @@
import MessageItem from "./MessageItem.vue";
import FileUpload from "../common/FileUpload.vue";
import Emotion from "../common/Emotion.vue";
export default {
name: "chatPrivate",
components: {
@ -70,12 +70,13 @@
},
data() {
return {
sendText: "",
showSide: false,
friend: {},
group: {},
groupMembers: [],
showEmotion: false,
emoBoxPos: {
sendText: "",
showSide: false, //
showEmotion: false, // emoji
emoBoxPos: { // emoji
x: 0,
y: 0
}
@ -84,17 +85,19 @@
methods: {
handleImageSuccess(res, file) {
let msgInfo = {
groupId: file.raw.targetId,
recvId: file.raw.targetId,
content: JSON.stringify(res.data),
type: 1
}
// id
this.setTargetId(msgInfo, this.chat.targetId);
this.$http({
url: '/message/group/send',
url: this.messageAction,
method: 'post',
data: msgInfo
}).then((data) => {
let info = {
type: 'GROUP',
type: this.chat.type,
targetId: file.raw.targetId,
fileId: file.raw.uid,
content: JSON.stringify(res.data),
@ -105,7 +108,7 @@
},
handleImageFail(res, file) {
let info = {
type: 'GROUP',
type: this.chat.type,
targetId: file.raw.targetId,
fileId: file.raw.uid,
loadStatus: "fail"
@ -121,13 +124,14 @@
let msgInfo = {
fileId: file.uid,
sendId: this.mine.id,
groupId: this.chat.targetId,
content: JSON.stringify(data),
sendTime: new Date().getTime(),
selfSend: true,
type: 1,
loadStatus: "loading"
}
// id
this.setTargetId(msgInfo, this.chat.targetId);
//
this.$store.commit("insertMessage", msgInfo);
//
@ -142,17 +146,18 @@
url: res.data
}
let msgInfo = {
groupId: file.raw.targetId,
content: JSON.stringify(data),
type: 2
}
// id
this.setTargetId(msgInfo, this.chat.targetId);
this.$http({
url: '/message/group/send',
url: this.messageAction,
method: 'post',
data: msgInfo
}).then(() => {
let info = {
type: 'GROUP',
type: this.chat.type,
targetId: file.raw.targetId,
fileId: file.raw.uid,
content: JSON.stringify(data),
@ -163,7 +168,7 @@
},
handleFileFail(res, file) {
let info = {
type: 'GROUP',
type: this.chat.type,
targetId: file.raw.targetId,
fileId: file.raw.uid,
loadStatus: "fail"
@ -180,13 +185,14 @@
let msgInfo = {
fileId: file.uid,
sendId: this.mine.id,
groupId: this.chat.targetId,
content: JSON.stringify(data),
sendTime: new Date().getTime(),
selfSend: true,
type: 2,
loadStatus: "loading"
}
// id
this.setTargetId(msgInfo, this.chat.targetId);
//
this.$store.commit("insertMessage", msgInfo);
//
@ -207,6 +213,15 @@
},
handleEmotion(emoText) {
this.sendText += emoText;
//
this.$refs.sendBox.focus();
},
setTargetId(msgInfo, targetId) {
if (this.chat.type == "GROUP") {
msgInfo.groupId = targetId;
} else {
msgInfo.recvId = targetId;
}
},
sendTextMessage() {
@ -215,12 +230,13 @@
return
}
let msgInfo = {
groupId: this.chat.targetId,
content: this.sendText,
type: 0
}
// id
this.setTargetId(msgInfo, this.chat.targetId);
this.$http({
url: '/message/group/send',
url: this.messageAction,
method: 'post',
data: msgInfo
}).then((data) => {
@ -235,7 +251,7 @@
//
this.scrollToBottom();
})
const e = window.event || arguments[0]
const e = window.event || arguments[0];
if (e.key === 'Enter' || e.code === 'Enter' || e.keyCode === 13) {
e.returnValue = false;
e.preventDefault();
@ -249,6 +265,8 @@
}).then((group) => {
this.group = group;
this.$store.commit("updateChatFromGroup", group);
this.$store.commit("updateGroup", group);
});
this.$http({
@ -257,15 +275,34 @@
}).then((groupMembers) => {
this.groupMembers = groupMembers;
});
},
loadFriend(friendId) {
//
this.$http({
url: `/user/find/${friendId}`,
method: 'get'
}).then((friend) => {
this.friend = friend;
this.$store.commit("updateChatFromFriend", friend);
this.$store.commit("updateFriend", friend);
})
},
showName(msgInfo) {
let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
return member ? member.aliasName : "";
if (this.chat.type == 'Group') {
let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
return member ? member.aliasName : "";
} else {
return msgInfo.sendId == this.mine.id ? this.mine.nickName : this.chat.showName
}
},
headImage(msgInfo) {
let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
return member ? member.headImage : "";
if (this.chat.type == 'Group') {
let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
return member ? member.headImage : "";
} else {
return msgInfo.sendId == this.mine.id ? this.mine.headImageThumb : this.chat.headImage
}
},
scrollToBottom() {
this.$nextTick(() => {
@ -279,41 +316,134 @@
return this.$store.state.userStore.userInfo;
},
title() {
let size = this.groupMembers.filter(m => !m.quit).length;
return `${this.chat.showName}(${size})`;
let title = this.chat.showName;
if (this.chat.type == "GROUP") {
let size = this.groupMembers.filter(m => !m.quit).length;
title += `(${size})`;
}
return title;
},
imageAction() {
return `${process.env.VUE_APP_BASE_API}/image/upload`;
},
fileAction() {
return `${process.env.VUE_APP_BASE_API}/file/upload`;
},
messageAction() {
return `/message/${this.chat.type.toLowerCase()}/send`;
}
},
mounted() {
console.log("group mount...")
this.loadGroup(this.chat.targetId);
this.scrollToBottom();
watch: {
chat: {
handler(newChat, oldChat) {
if(newChat.type != oldChat.type || newChat.targetId != oldChat.targetId){
if (this.chat.type == "GROUP") {
this.loadGroup(this.chat.targetId);
} else {
this.loadFriend(this.chat.targetId);
}
this.scrollToBottom();
this.sendText = "";
//
this.$refs.sendBox.focus();
}
},
deep: true //
}
}
}
</script>
<style>
.btn-side {
position: absolute;
right: 20px;
line-height: 60px;
font-size: 22px;
cursor: pointer;
<style lang="scss">
.r-chat-box {
background: white;
border: #dddddd solid 1px;
.el-header {
padding: 5px;
background-color: white;
line-height: 50px;
font-size: 20px;
font-weight: 600;
border: #dddddd solid 1px;
&:hover {
font-size: 30px;
.btn-side {
position: absolute;
right: 20px;
line-height: 60px;
font-size: 22px;
cursor: pointer;
&:hover {
font-size: 30px;
}
}
}
}
.im-chat-main {
padding: 0;
border: #dddddd solid 1px;
.chat-group-side-box {
border: #dddddd solid 1px;
animation: rtl-drawer-in .3s 1ms;
.im-chat-box {
ul {
padding: 20px;
li {
list-style-type: none;
}
}
}
}
.im-chat-footer {
display: flex;
flex-direction: column;
padding: 0;
border: #dddddd solid 1px;
.chat-tool-bar {
display: flex;
position: relative;
width: 100%;
height: 40px;
text-align: left;
box-sizing: border-box;
border: #dddddd solid 1px;
>div {
margin-left: 10px;
font-size: 22px;
cursor: pointer;
color: #333333;
line-height: 40px;
&:hover {
color: black;
}
}
}
.send-text-area {
box-sizing: border-box;
padding: 5px;
width: 100%;
flex: 1;
resize: none;
background-color: #f8f8f8 !important;
outline-color: rgba(83, 160, 231, 0.61);
}
.im-chat-send {
text-align: right;
padding: 7px;
}
}
.chat-group-side-box {
border: #dddddd solid 1px;
animation: rtl-drawer-in .3s 1ms;
}
}
</style>

251
im-ui/src/components/chat/ChatPrivate.vue

@ -1,251 +0,0 @@
<template>
<el-container class="r-chat-box">
<el-header height="60px">
{{chat.showName}}
</el-header>
<el-main class="im-chat-main" id="chatScrollBox">
<div class="im-chat-box">
<ul>
<li v-for="msgInfo in chat.messages" :key="msgInfo.id">
<message-item :mine="msgInfo.sendId == mine.id" :headImage="headImage(msgInfo)" :showName="showName(msgInfo)"
:msgInfo="msgInfo">
</message-item>
</li>
</ul>
</div>
</el-main>
<el-footer height="25%" class="im-chat-footer">
<div class="chat-tool-bar">
<div class="el-icon-eleme" ref="emotion" @click="switchEmotionBox()">
<emotion v-show="showEmotion" :pos="emoBoxPos" @emotion="handleEmotion"></Emotion>
</div>
<div>
<file-upload :action="imageAction" :maxSize="5*1024*1024" :fileTypes="['image/jpeg', 'image/png', 'image/jpg','image/webp', 'image/gif']"
@before="handleImageBefore" @success="handleImageSuccess" @fail="handleImageFail">
<i class="el-icon-picture-outline"></i>
</file-upload>
</div>
<div>
<file-upload :action="fileAction" :maxSize="10*1024*1024" @before="handleFileBefore" @success="handleFileSuccess"
@fail="handleFileFail">
<i class="el-icon-wallet"></i>
</file-upload>
</div>
<div class="el-icon-chat-dot-round"></div>
</div>
<textarea v-model="sendText" ref="sendBox" class="send-text-area" @keyup.enter="sendTextMessage()"></textarea>
<div class="im-chat-send">
<el-button type="primary" @click="sendTextMessage()">发送</el-button>
</div>
</el-footer>
</el-container>
</template>
<script>
import MessageItem from "./MessageItem.vue";
import FileUpload from "../common/FileUpload.vue";
import Emotion from "../common/Emotion.vue";
export default {
name: "chatPrivate",
components: {
MessageItem,
FileUpload,
Emotion
},
props: {
chat: {
type: Object
}
},
data() {
return {
sendText: "",
showEmotion: false,
emoBoxPos: {
x: 0,
y: 0
}
}
},
methods: {
handleImageSuccess(res, file) {
let msgInfo = {
recvId: file.raw.targetId,
content: JSON.stringify(res.data),
type: 1
}
this.$http({
url: '/message/private/send',
method: 'post',
data: msgInfo
}).then((data) => {
let info = {
type: 'PRIVATE',
targetId: file.raw.targetId,
fileId: file.raw.uid,
content: JSON.stringify(res.data),
loadStatus: "ok"
}
this.$store.commit("handleFileUpload", info);
})
},
handleImageFail(res, file) {
let info = {
type: 'PRIVATE',
targetId: file.raw.targetId,
fileId: file.raw.uid,
loadStatus: "fail"
}
this.$store.commit("handleFileUpload", info);
},
handleImageBefore(file) {
let url = URL.createObjectURL(file);
let data = {
originUrl: url,
thumbUrl: url
}
let msgInfo = {
fileId: file.uid,
sendId: this.mine.id,
recvId: this.chat.targetId,
content: JSON.stringify(data),
sendTime: new Date().getTime(),
selfSend: true,
type: 1,
loadStatus: "loading"
}
//
this.$store.commit("insertMessage", msgInfo);
//
this.scrollToBottom();
// fileid
file.targetId = this.chat.targetId;
},
handleFileSuccess(res, file) {
console.log(res.data);
let data = {
name: file.name,
size: file.size,
url: res.data
}
let msgInfo = {
recvId: file.raw.targetId,
content: JSON.stringify(data),
type: 2
}
this.$http({
url: '/message/private/send',
method: 'post',
data: msgInfo
}).then(() => {
let info = {
type: 'PRIVATE',
targetId: file.raw.targetId,
fileId: file.raw.uid,
content: JSON.stringify(data),
loadStatus: "ok"
}
this.$store.commit("handleFileUpload", info);
})
},
handleFileFail(res, file) {
let info = {
type: 'PRIVATE',
targetId: file.raw.targetId,
fileId: file.raw.uid,
loadStatus: "fail"
}
this.$store.commit("handleFileUpload", info);
},
handleFileBefore(file) {
let url = URL.createObjectURL(file);
let data = {
name: file.name,
size: file.size,
url: url
}
let msgInfo = {
fileId: file.uid,
sendId: this.mine.id,
recvId: this.chat.targetId,
content: JSON.stringify(data),
sendTime: new Date().getTime(),
selfSend: true,
type: 2,
loadStatus: "loading"
}
//
this.$store.commit("insertMessage", msgInfo);
//
this.scrollToBottom();
// fileid
file.targetId = this.chat.targetId;
},
switchEmotionBox() {
this.showEmotion = !this.showEmotion;
let width = this.$refs.emotion.offsetWidth;
let left = this.$elm.fixLeft(this.$refs.emotion);
let top = this.$elm.fixTop(this.$refs.emotion);
this.emoBoxPos.y = top;
this.emoBoxPos.x = left + width/2;
},
handleEmotion(emoText) {
this.sendText += emoText;
},
sendTextMessage() {
let msgInfo = {
recvId: this.chat.targetId,
content: this.sendText,
type: 0
}
this.$http({
url: '/message/private/send',
method: 'post',
data: msgInfo
}).then((data) => {
this.$message.success("发送成功");
this.sendText = "";
msgInfo.sendTime = new Date().getTime();
msgInfo.sendId = this.$store.state.userStore.userInfo.id;
msgInfo.selfSend = true;
this.$store.commit("insertMessage", msgInfo);
//
this.$refs.sendBox.focus();
//
this.scrollToBottom();
})
},
showName(msg) {
return msg.sendId == this.mine.id ? this.mine.nickName : this.chat.showName
},
headImage(msg) {
return msg.sendId == this.mine.id ? this.mine.headImageThumb : this.chat.headImage
},
scrollToBottom() {
this.$nextTick(() => {
const div = document.getElementById("chatScrollBox");
div.scrollTop = div.scrollHeight;
});
}
},
computed: {
mine() {
return this.$store.state.userStore.userInfo;
},
imageAction() {
return `${process.env.VUE_APP_BASE_API}/image/upload`;
},
fileAction() {
return `${process.env.VUE_APP_BASE_API}/file/upload`;
}
},
mounted() {
console.log("private mount...")
this.scrollToBottom();
}
}
</script>
<style>
</style>

8
im-ui/src/store/chatStore.js

@ -102,12 +102,12 @@ export default {
msg.content = info.content;
}
},
updateChatFromUser(state, user) {
updateChatFromFriend(state, friend) {
for (let i in state.chats) {
let chat = state.chats[i];
if (chat.type=='PRIVATE' && chat.targetId == user.id) {
chat.headImage = user.headImageThumb;
chat.showName = user.nickName;
if (chat.type=='PRIVATE' && chat.targetId == friend.id) {
chat.headImage = friend.headImageThumb;
chat.showName = friend.nickName;
break;
}
}

147
im-ui/src/view/Chat.vue

@ -14,31 +14,20 @@
</el-scrollbar>
</el-aside>
<el-container class="r-chat-box">
<chat-private :chat="activeChat" v-if="activeChat.type=='PRIVATE'"></chat-private>
<chat-Group :chat="activeChat" v-if="activeChat.type=='GROUP'"></chat-Group>
<chat-box :chat="activeChat"></chat-box>
</el-container>
</el-container>
</template>
<script>
import ChatItem from "../components/chat/ChatItem.vue";
import ChatTime from "../components/chat/ChatTime.vue";
import MessageItem from "../components/chat/MessageItem.vue";
import HeadImage from "../components/common/HeadImage.vue";
import FileUpload from "../components/common/FileUpload.vue";
import ChatPrivate from "../components/chat/ChatPrivate.vue";
import ChatGroup from "../components/chat/ChatGroup.vue";
import ChatBox from "../components/chat/ChatBox.vue";
export default {
name: "chat",
components: {
ChatItem,
ChatTime,
HeadImage,
FileUpload,
MessageItem,
ChatPrivate,
ChatGroup
ChatBox
},
data() {
return {
@ -51,67 +40,10 @@
methods: {
handleActiveItem(index) {
this.$store.commit("activeChat", index);
let chat = this.chatStore.chats[index];
if (chat.type == "PRIVATE") {
this.refreshNameAndHeadImage(chat);
}
},
handleDelItem(chat, index) {
this.$store.commit("removeChat", index);
},
sendGroupMessage() {
let msgInfo = {
groupId: this.activeChat.targetId,
content: this.messageContent,
type: 0
}
this.$http({
url: '/message/group/send',
method: 'post',
data: msgInfo
}).then((data) => {
this.$message.success("发送成功");
this.messageContent = "";
msgInfo.sendTime = new Date().getTime();
msgInfo.sendId = this.$store.state.userStore.userInfo.id;
msgInfo.selfSend = true;
this.$store.commit("insertMessage", msgInfo);
//
this.$refs.sendBox.focus();
//
this.scrollToBottom();
})
},
refreshNameAndHeadImage(chat){
//
let userId = chat.targetId;
this.$http({
url: `/user/find/${userId}`,
method: 'get'
}).then((user) => {
//
if (user.headImageThumb != chat.headImage ||
user.nickName != chat.showName) {
this.updateFriendInfo(user)
this.$store.commit("updateChatFromUser", user);
}
})
},
updateFriendInfo(user) {
let friendInfo = {
id: user.id,
nickName: user.nickName,
headImage: user.headImageThumb
};
this.$http({
url: "/friend/update",
method: "put",
data: friendInfo
}).then(() => {
this.$store.commit("updateFriend", friendInfo);
})
}
},
computed: {
chatStore() {
@ -155,78 +87,5 @@
flex: 1;
}
}
.r-chat-box {
background: white;
border: #dddddd solid 1px;
.el-header {
padding: 5px;
background-color: white;
line-height: 50px;
font-size: 20px;
font-weight: 600;
border: #dddddd solid 1px;
}
.im-chat-main {
padding: 0;
border: #dddddd solid 1px;
.im-chat-box {
ul {
padding: 20px;
li {
list-style-type: none;
}
}
}
}
.im-chat-footer {
display: flex;
flex-direction: column;
padding: 0;
border: #dddddd solid 1px;
.chat-tool-bar {
display: flex;
position: relative;
width: 100%;
height: 40px;
text-align: left;
box-sizing: border-box;
border: #dddddd solid 1px;
>div {
margin-left: 10px;
font-size: 22px;
cursor: pointer;
color: #333333;
line-height: 40px;
&:hover {
color: black;
}
}
}
.send-text-area {
box-sizing: border-box;
padding: 5px;
width: 100%;
flex: 1;
resize: none;
background-color: #f8f8f8 !important;
outline-color: rgba(83, 160, 231, 0.61);
}
.im-chat-send {
text-align: right;
padding: 7px;
}
}
}
}
</style>

2
im-ui/src/view/Friend.vue

@ -122,7 +122,7 @@
data: friend
}).then(() => {
this.$store.commit("updateFriend", friend);
this.$store.commit("updateChatFromUser", user);
this.$store.commit("updateChatFromFriend", user);
})
},
loadUserInfo(friend,index){

Loading…
Cancel
Save