From a0debd09a09479808e8c7e23f1fe6d56e0567608 Mon Sep 17 00:00:00 2001
From: xsx <825657193@qq.com>
Date: Sun, 12 Nov 2023 23:35:57 +0800
Subject: [PATCH] =?UTF-8?q?=E7=BE=A4=E8=81=8A@=E5=8A=9F=E8=83=BD(=E5=AE=8C?=
=?UTF-8?q?=E6=88=90)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 9 +-
im-ui/src/components/chat/ChatBox.vue | 3 -
im-ui/src/view/Login.vue | 7 +
im-uniapp/common/wssocket.js | 33 ++--
.../components/chat-at-box/chat-at-box.vue | 176 ++++++++++++++++++
.../chat-message-item/chat-message-item.vue | 2 +-
.../components/head-image/head-image.vue | 6 +-
im-uniapp/pages/chat/chat-box.vue | 115 ++++++++++--
im-uniapp/pages/group/group-invite.vue | 4 +-
im-uniapp/static/icon/iconfont.css | 6 +-
im-uniapp/static/icon/iconfont.ttf | Bin 5360 -> 5644 bytes
im-uniapp/store/chatStore.js | 1 +
12 files changed, 313 insertions(+), 49 deletions(-)
create mode 100644 im-uniapp/components/chat-at-box/chat-at-box.vue
diff --git a/README.md b/README.md
index 7df8fde..87f6af2 100644
--- a/README.md
+++ b/README.md
@@ -13,14 +13,13 @@
#### 近期更新
-发布2.0版本,本次更新主要是加入了uniapp版本:
+发布2.0版本,本次更新加入了uniapp版本:
- 支持移动端和web端同时在线,多端消息同步
- 目前仅兼容h5和微信小程序,后续会继续兼容更多终端类型
-- 页面风格优化:表情包更新、自动生成文字头像等
-
-感兴趣的小伙伴,可在下方扫码体验
-
+- 聊天窗口加入已读未读显示
+- 群聊加入@功能
+- 界面风格升级,表情包更新、生成文字头像等
#### 在线体验
diff --git a/im-ui/src/components/chat/ChatBox.vue b/im-ui/src/components/chat/ChatBox.vue
index 346d039..82744db 100644
--- a/im-ui/src/components/chat/ChatBox.vue
+++ b/im-ui/src/components/chat/ChatBox.vue
@@ -219,7 +219,6 @@
},
createSendText() {
let sendText = ""
- console.log(this.$refs.editBox.childNodes);
this.$refs.editBox.childNodes.forEach((node) => {
if (node.nodeName == "#text") {
sendText += node.textContent;
@@ -233,10 +232,8 @@
},
createAtUserIds() {
let ids = [];
- console.log(this.$refs.editBox.childNodes);
this.$refs.editBox.childNodes.forEach((node) => {
if (node.nodeName == "SPAN") {
- console.log(node);
ids.push(node.dataset.id);
}
})
diff --git a/im-ui/src/view/Login.vue b/im-ui/src/view/Login.vue
index 9ae9728..dc80110 100644
--- a/im-ui/src/view/Login.vue
+++ b/im-ui/src/view/Login.vue
@@ -17,6 +17,13 @@
修改拉取离线消息机制:用户登录后,自动从服务器同步最近1个月的消息
+
+
最近更新(2023-11-12):
+
+ - 群聊加入@功能
+ - 聊天输入框支持显示emoji表情
+
+
项目依旧完全开源,可内网部署。如果项目对您有帮助,请帮忙点个star:
diff --git a/im-uniapp/common/wssocket.js b/im-uniapp/common/wssocket.js
index 1f3a04a..deedfae 100644
--- a/im-uniapp/common/wssocket.js
+++ b/im-uniapp/common/wssocket.js
@@ -4,9 +4,14 @@ let messageCallBack = null;
let closeCallBack = null;
let isConnect = false; //连接标识 避免重复连接
let rec = null;
+let isInit = false;
let init = () => {
-
+ // 防止重复初始化
+ if (isInit) {
+ return;
+ }
+ isInit = true;
uni.onSocketOpen((res) => {
console.log("WebSocket连接已打开");
isConnect = true;
@@ -21,7 +26,7 @@ let init = () => {
data: JSON.stringify(loginInfo)
});
})
-
+
uni.onSocketMessage((res) => {
let sendInfo = JSON.parse(res.data)
if (sendInfo.cmd == 0) {
@@ -32,17 +37,17 @@ let init = () => {
heartCheck.reset();
} else {
// 其他消息转发出去
- console.log("接收到消息",sendInfo);
+ console.log("接收到消息", sendInfo);
messageCallBack && messageCallBack(sendInfo.cmd, sendInfo.data)
}
})
-
+
uni.onSocketClose((res) => {
console.log('WebSocket连接关闭')
isConnect = false; //断开后修改标识
closeCallBack && closeCallBack(res);
})
-
+
uni.onSocketError((e) => {
console.log(e)
isConnect = false; //连接断开修改标识
@@ -53,7 +58,7 @@ let init = () => {
})
};
-let connect = (url, token)=>{
+let connect = (url, token) => {
wsurl = url;
accessToken = token;
if (isConnect) {
@@ -67,23 +72,23 @@ let connect = (url, token)=>{
fail: (e) => {
console.log(e);
console.log("websocket连接失败,10s后重连");
- setTimeout(()=>{
+ setTimeout(() => {
connect();
- },10000)
+ }, 10000)
}
});
}
//定义重连函数
-let reconnect = (wsurl,accessToken) => {
+let reconnect = (wsurl, accessToken) => {
console.log("尝试重新连接");
- if (isConnect){
+ if (isConnect) {
//如果已经连上就不在重连了
- return;
+ return;
}
rec && clearTimeout(rec);
rec = setTimeout(function() { // 延迟15秒重连 避免过多次过频繁请求重连
- connect(wsurl,accessToken);
+ connect(wsurl, accessToken);
}, 15000);
};
@@ -98,8 +103,8 @@ let close = () => {
console.log("关闭websocket连接");
isConnect = false;
},
- fail:(e)=>{
- console.log("关闭websocket连接失败",e);
+ fail: (e) => {
+ console.log("关闭websocket连接失败", e);
}
});
};
diff --git a/im-uniapp/components/chat-at-box/chat-at-box.vue b/im-uniapp/components/chat-at-box/chat-at-box.vue
new file mode 100644
index 0000000..51ad5b2
--- /dev/null
+++ b/im-uniapp/components/chat-at-box/chat-at-box.vue
@@ -0,0 +1,176 @@
+
+
+
+
+ 选择要提醒的人
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ m.aliasName}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/im-uniapp/components/chat-message-item/chat-message-item.vue b/im-uniapp/components/chat-message-item/chat-message-item.vue
index c627bc6..8085022 100644
--- a/im-uniapp/components/chat-message-item/chat-message-item.vue
+++ b/im-uniapp/components/chat-message-item/chat-message-item.vue
@@ -7,7 +7,7 @@
-
+
{{showName}}
diff --git a/im-uniapp/components/head-image/head-image.vue b/im-uniapp/components/head-image/head-image.vue
index b3dd3d1..cdb3248 100644
--- a/im-uniapp/components/head-image/head-image.vue
+++ b/im-uniapp/components/head-image/head-image.vue
@@ -1,5 +1,5 @@
-
+
@@ -26,7 +26,7 @@
},
size: {
type: Number,
- default: 50
+ default: 20
},
url: {
type: String
@@ -77,6 +77,8 @@
position: relative;
overflow: hidden;
border-radius: 10%;
+ border: 1px solid #ccc;
+ vertical-align: bottom;
}
.avatar-text {
diff --git a/im-uniapp/pages/chat/chat-box.vue b/im-uniapp/pages/chat/chat-box.vue
index af562d5..a2a84a5 100644
--- a/im-uniapp/pages/chat/chat-box.vue
+++ b/im-uniapp/pages/chat/chat-box.vue
@@ -1,5 +1,5 @@
-
+
+ :scroll-into-view="'chat-item-'+scrollMsgIdx">
-
+
+
+ :
+
+
+
+
+
+
+
+
-
+
-
+
-
@@ -53,7 +64,6 @@
文件
-
语音输入
@@ -62,9 +72,7 @@
呼叫
-
-
-
+
@@ -92,6 +101,7 @@
chatTabBox: 'none',
showKeyBoard: false,
keyboardHeight: 322,
+ atUserIds: [],
showMinIdx: 0 // 下标小于showMinIdx的消息不显示,否则可能很卡
}
},
@@ -102,6 +112,18 @@
icon: "none"
})
},
+ openAtBox() {
+ this.$refs.atBox.init(this.atUserIds);
+ this.$refs.atBox.open();
+ },
+ onAtComplete(atUserIds) {
+ this.atUserIds = atUserIds;
+ },
+ onLongPressHead(msgInfo){
+ if(!msgInfo.selfSend && this.chat.type=="GROUP" && this.atUserIds.indexOf(msgInfo.sendId)<0){
+ this.atUserIds.push(msgInfo.sendId);
+ }
+ },
headImage(msgInfo) {
if (this.chat.type == 'GROUP') {
let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
@@ -117,17 +139,19 @@
} else {
return msgInfo.selfSend ? this.mine.nickName : this.chat.showName
}
-
},
sendTextMessage() {
- if (!this.sendText.trim()) {
+ if (!this.sendText.trim() && this.atUserIds.length==0) {
return uni.showToast({
title: "不能发送空白信息",
icon: "none"
});
+
}
+ let atText = this.createAtText()
let msgInfo = {
- content: this.sendText,
+ content: this.sendText + atText,
+ atUserIds: this.atUserIds,
type: 0
}
// 填充对方id
@@ -148,8 +172,20 @@
}).finally(() => {
// 滚动到底部
this.scrollToBottom();
+ // 清空@用户列表
+ this.atUserIds = [];
});
},
+ createAtText() {
+ let atText = "";
+ this.atUserIds.forEach((id) => {
+ let member = this.groupMembers.find((m)=>m.userId==id);
+ if (member) {
+ atText += ` @${member.aliasName}`;
+ }
+ })
+ return atText;
+ },
fillTargetId(msgInfo, targetId) {
if (this.chat.type == "GROUP") {
msgInfo.groupId = targetId;
@@ -175,7 +211,7 @@
return;
}
this.$nextTick(() => {
- console.log("scrollToMsgIdx",this.scrollMsgIdx)
+ console.log("scrollToMsgIdx", this.scrollMsgIdx)
this.scrollMsgIdx = idx;
});
@@ -450,6 +486,20 @@
},
unreadCount() {
return this.chat.unreadCount;
+ },
+ atUserItems(){
+ let atUsers = [];
+ this.atUserIds.forEach((id)=>{
+ if(id==-1){
+ atUsers.push({id:-1,aliasName:"全体成员"})
+ return;
+ }
+ let member = this.groupMembers.find((m)=>m.userId==id);
+ if(member){
+ atUsers.push(member);
+ }
+ })
+ return atUsers;
}
},
watch: {
@@ -543,6 +593,34 @@
}
}
+ .chat-at-bar {
+ display: flex;
+ align-items: center;
+ padding: 0 10rpx;
+ border: #dddddd solid 1px;
+
+ .icon-at {
+ font-size: 35rpx;
+ color: darkblue;
+ font-weight: 600;
+ }
+
+ .chat-at-scroll-box {
+ flex: 1;
+ width: 80%;
+ .chat-at-items {
+ display: flex;
+ align-items: center;
+ height: 70rpx;
+
+ .chat-at-item {
+ padding: 0 3rpx;
+ }
+ }
+ }
+
+ }
+
.send-bar {
display: flex;
align-items: center;
@@ -552,7 +630,7 @@
background-color: white;
.iconfont {
- font-size: 70rpx;
+ font-size: 60rpx;
margin: 3rpx;
}
@@ -571,7 +649,6 @@
.send-text-area {
width: 100%;
}
-
}
.btn-send {
@@ -586,7 +663,6 @@
background-color: whitesmoke;
.chat-tools {
-
display: flex;
flex-wrap: wrap;
justify-content: space-between;
@@ -609,7 +685,6 @@
height: 60rpx;
line-height: 60rpx;
font-size: 25rpx;
-
}
}
}
diff --git a/im-uniapp/pages/group/group-invite.vue b/im-uniapp/pages/group/group-invite.vue
index b2e5af7..93596d8 100644
--- a/im-uniapp/pages/group/group-invite.vue
+++ b/im-uniapp/pages/group/group-invite.vue
@@ -17,9 +17,7 @@
-
-
-
+
diff --git a/im-uniapp/static/icon/iconfont.css b/im-uniapp/static/icon/iconfont.css
index e41ef1b..b437e6f 100644
--- a/im-uniapp/static/icon/iconfont.css
+++ b/im-uniapp/static/icon/iconfont.css
@@ -1,6 +1,6 @@
@font-face {
font-family: "iconfont"; /* Project id 4272106 */
- src: url('iconfont.ttf?t=1697348383625') format('truetype');
+ src: url('iconfont.ttf?t=1699795609670') format('truetype');
}
.iconfont {
@@ -11,6 +11,10 @@
-moz-osx-font-smoothing: grayscale;
}
+.icon-at:before {
+ content: "\e7de";
+}
+
.icon-man:before {
content: "\e615";
}
diff --git a/im-uniapp/static/icon/iconfont.ttf b/im-uniapp/static/icon/iconfont.ttf
index 289cebb490ce2b385557bc899ab9e6723bc6d46f..de77a9226db541c032ffe72cd3c437bce9f11dce 100644
GIT binary patch
delta 922
zcmaKqUr1AN6vxl+-s|0JQ+M5+CQO-ka;IUs|67~(ciONR<-ZgkWSBZ*>P#~wazav&
zJs5-PAwsbC{`ewcAQ94oNca*(NJ0GkLl5>~PtiKRU3%?~&;6Zqe&=`2_x$emtMAv$
zJJU^PQl9`gC-QnAIn^JI`JMyhnE>+F6MgY3s=he@0ACS*0t33w{A09Nkjli+_+&(%
zJpdp-(2pcXdgG<<%lrTW^DBqqlPRLY8txxK-!>c{>N73YzW^xug8c?kBV+mFRrmI{
z04xzqSbMNyKPdr06S1s6Q+o>Q55OQ`0N~ri?b3g1_E+|nAo6qQ>w#lYeAqcDQ%*i+
zev;VPy_^s59r&D8gX>{T+5-WWF;f8>S{wz+Q4_V$QW~aF+Demjlupq!UD)2r%y5c+
zduu1U+mOv>B);Mt!DIjbF+n^SQIrAOnV=BzuuVP`z#)_&f(|8!SnGFYmD8n-OgDVU
zy#cdTlqVJ
zBD~967Td%pB4xs}%lsQY9fga~1z?s-%8ADv@CW=puWDCxqE56cszdd8G30TV6qgiR
zvtE+VkCTgW7g}ct8hq0y|KpT
zI6CplX~_7+jm4-3W%r%TOe8
zy|IZ*&n5bXb)vy&HJW&XAa=KR-WXeQd8(@~TuPqm^*ijuF3Gaws;UhQ-n|<3)E@Ii
yXIgIdboXBy82q!@^{A`!VK@Hqar#yMEq@x8vO=toNST;y6G;(p@$t-vJo6V8t;>i2
delta 607
zcmZvXKS-NF7{;Hw@5^UwqWLOKQIIq>W+=_z>oZ@mQbSR|?cKLiRM>p^I-M#Pqd7tO4=6*l>+*MgRSjhu2
zN45*4g^3S8;wixW3&f9$`QUB#>)H^28tE?bpyAwEWxP*1i{-ib!Dx65h+oVHOH*%x
zw&CPY{y%2kQ4Z#(MHb(A-^x5a8I<$>R^JZr@Ei3C(^K!7<}!aWuYpH2fTNZD%zzKU
zkUUmL!FZzY8Znm#z{S|}jsJUi6TWvn=M(cNq&ej<|9q7aXX;jrW^45vIEPb@a@-&A
zQ4KD>@MW6QRaM!pKFSX7a^$K%4AriDG9>C(=KB5#G*B`I!E%jApqT|7#L+}65qOmF
z)Kll5I+Tr-xbX!xTOSEPGcd3QG>scf1KPK+E_BjD1?V=5v95b9RD~X~P#^k*g-)PL
z7J7o7DVT)<4)+BMjY3x}v<$szp?O@gsDW+Zs^4N7;&_R5krvD1M7GFTx$Z=rZFe}*
Z6FK!#UJ-jS?^QzhY9g5yP}St3z#Se?dZqvX
diff --git a/im-uniapp/store/chatStore.js b/im-uniapp/store/chatStore.js
index 85a7b99..67a2bf3 100644
--- a/im-uniapp/store/chatStore.js
+++ b/im-uniapp/store/chatStore.js
@@ -158,6 +158,7 @@ export default {
chat.atAll = true;
}
}
+
// 记录消息的最大id
if (msgInfo.id && type == "PRIVATE" && msgInfo.id > state.privateMsgMaxId) {
state.privateMsgMaxId = msgInfo.id;