From c421a5dbdd71012ae48a6b78088f6864ee8627e3 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Thu, 3 Apr 2025 22:11:29 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BE=A4=E8=81=8A=E4=BC=98=E5=8C=96=EF=BC=8C?= =?UTF-8?q?=E7=BE=A4=E4=BA=BA=E5=91=98=E9=99=90=E5=88=B6=E6=94=BE=E5=AE=BD?= =?UTF-8?q?=E8=87=B31=E4=B8=87=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bx/implatform/contant/Constant.java | 8 +- .../service/impl/GroupMessageServiceImpl.java | 5 + .../components/chat-at-box/chat-at-box.vue | 33 +- .../chat-group-readed/chat-group-readed.vue | 24 +- .../group-member-selector.vue | 34 +- .../virtual-scroller/virtual-scroller.vue | 56 +++ im-uniapp/pages/chat/chat-box.vue | 5 +- im-uniapp/pages/chat/chat.vue | 35 +- im-uniapp/pages/common/external-link.vue | 20 ++ im-uniapp/pages/group/group-member.vue | 35 +- im-uniapp/store/chatStore.js | 1 + im-web/src/components/chat/ChatAtBox.vue | 6 +- im-web/src/components/chat/ChatBox.vue | 18 +- .../src/components/chat/ChatGroupReaded.vue | 318 +++++++++--------- im-web/src/components/chat/ChatGroupSide.vue | 50 ++- .../src/components/common/VirtualScroller.vue | 74 ++++ .../components/group/GroupMemberSelector.vue | 27 +- im-web/src/view/Group.vue | 48 ++- 18 files changed, 513 insertions(+), 284 deletions(-) create mode 100644 im-uniapp/components/virtual-scroller/virtual-scroller.vue create mode 100644 im-uniapp/pages/common/external-link.vue create mode 100644 im-web/src/components/common/VirtualScroller.vue diff --git a/im-platform/src/main/java/com/bx/implatform/contant/Constant.java b/im-platform/src/main/java/com/bx/implatform/contant/Constant.java index 08e4125..e5e57ba 100644 --- a/im-platform/src/main/java/com/bx/implatform/contant/Constant.java +++ b/im-platform/src/main/java/com/bx/implatform/contant/Constant.java @@ -14,9 +14,15 @@ public final class Constant { * 最大上传文件大小 */ public static final Long MAX_FILE_SIZE = 20 * 1024 * 1024L; + /** * 群聊最大人数 */ - public static final Long MAX_GROUP_MEMBER = 500L; + public static final Long MAX_GROUP_MEMBER = 10000L; + + /** + * 回执消息限制最大人数 + */ + public static final Long LARGE_GROUP_MEMBER = 500L; } diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java index 15e800a..805de09 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java @@ -14,6 +14,7 @@ import com.bx.imcommon.enums.IMTerminalType; import com.bx.imcommon.model.IMGroupMessage; import com.bx.imcommon.model.IMUserInfo; import com.bx.imcommon.util.CommaTextUtils; +import com.bx.implatform.contant.Constant; import com.bx.implatform.contant.RedisKey; import com.bx.implatform.dto.GroupMessageDTO; import com.bx.implatform.entity.Group; @@ -64,6 +65,10 @@ public class GroupMessageServiceImpl extends ServiceImpl userIds = groupMemberService.findUserIdsByGroupId(group.getId()); + if (dto.getReceipt() && userIds.size() > Constant.LARGE_GROUP_MEMBER) { + // 大群的回执消息过于消耗资源,不允许发送 + throw new GlobalException(String.format("当前群聊大于%s人,不支持发送回执消息", Constant.LARGE_GROUP_MEMBER)); + } // 不用发给自己 userIds = userIds.stream().filter(id -> !session.getUserId().equals(id)).collect(Collectors.toList()); // 保存消息 diff --git a/im-uniapp/components/chat-at-box/chat-at-box.vue b/im-uniapp/components/chat-at-box/chat-at-box.vue index ad1a9ed..f056c91 100644 --- a/im-uniapp/components/chat-at-box/chat-at-box.vue +++ b/im-uniapp/components/chat-at-box/chat-at-box.vue @@ -9,7 +9,7 @@ - + @@ -18,18 +18,15 @@ - - - - + + @@ -91,13 +88,13 @@ export default { }, computed: { atUserIds() { - let ids = []; - this.showMembers.forEach((m) => { - if (m.checked) { - ids.push(m.userId); - } - }) - return ids; + return this.showMembers.filter(m => m.checked).map(m => m.userId); + }, + checkedMembers() { + return this.showMembers.filter(m => m.checked); + }, + memberItems() { + return this.showMembers.filter(m => m.showNickName.includes(this.searchText)); } } } diff --git a/im-uniapp/components/chat-group-readed/chat-group-readed.vue b/im-uniapp/components/chat-group-readed/chat-group-readed.vue index 4ae285e..13b67ac 100644 --- a/im-uniapp/components/chat-group-readed/chat-group-readed.vue +++ b/im-uniapp/components/chat-group-readed/chat-group-readed.vue @@ -7,26 +7,26 @@ - - + + + - - + + + diff --git a/im-uniapp/components/group-member-selector/group-member-selector.vue b/im-uniapp/components/group-member-selector/group-member-selector.vue index ca87122..273b3cc 100644 --- a/im-uniapp/components/group-member-selector/group-member-selector.vue +++ b/im-uniapp/components/group-member-selector/group-member-selector.vue @@ -9,7 +9,7 @@ - + @@ -18,18 +18,20 @@ - - - - + + @@ -93,13 +95,13 @@ export default { }, computed: { checkedIds() { - let ids = []; - this.members.forEach((m) => { - if (m.checked) { - ids.push(m.userId); - } - }) - return ids; + return this.members.filter((m) => m.checked).map(m => m.userId) + }, + checkedMembers() { + return this.members.filter((m) => m.checked); + }, + showMembers() { + return this.members.filter(m => !m.quit && m.showNickName.includes(this.searchText)) } } } diff --git a/im-uniapp/components/virtual-scroller/virtual-scroller.vue b/im-uniapp/components/virtual-scroller/virtual-scroller.vue new file mode 100644 index 0000000..049eb3f --- /dev/null +++ b/im-uniapp/components/virtual-scroller/virtual-scroller.vue @@ -0,0 +1,56 @@ + + + + + \ No newline at end of file diff --git a/im-uniapp/pages/chat/chat-box.vue b/im-uniapp/pages/chat/chat-box.vue index 5b84715..d7fe853 100644 --- a/im-uniapp/pages/chat/chat-box.vue +++ b/im-uniapp/pages/chat/chat-box.vue @@ -71,7 +71,7 @@ 语音消息 - + 回执消息 @@ -886,6 +886,9 @@ export default { } }) return atUsers; + }, + memberSize() { + return this.groupMembers.filter(m => !m.quit).length; } }, watch: { diff --git a/im-uniapp/pages/chat/chat.vue b/im-uniapp/pages/chat/chat.vue index 43912d9..b798427 100644 --- a/im-uniapp/pages/chat/chat.vue +++ b/im-uniapp/pages/chat/chat.vue @@ -31,7 +31,6 @@ - \ No newline at end of file diff --git a/im-uniapp/pages/group/group-member.vue b/im-uniapp/pages/group/group-member.vue index d90a813..860ab5a 100644 --- a/im-uniapp/pages/group/group-member.vue +++ b/im-uniapp/pages/group/group-member.vue @@ -8,24 +8,22 @@ - - - - - {{ member.showNickName }} - + + + @@ -37,7 +35,7 @@ export default { isModify: false, searchText: "", group: {}, - groupMembers: [] + members: [] } }, methods: { @@ -46,7 +44,7 @@ export default { url: "/pages/common/user-info?id=" + userId }) }, - onKickOut(member, idx) { + onKickOut(member) { uni.showModal({ title: '确认移出?', content: `确定将成员'${member.showNickName}'移出群聊吗?`, @@ -61,7 +59,7 @@ export default { title: `已将${member.showNickName}移出群聊`, icon: 'none' }) - this.groupMembers.splice(idx, 1); + member.quit = true; this.isModify = true; }); } @@ -80,7 +78,7 @@ export default { url: `/group/members/${id}`, method: "GET" }).then((members) => { - this.groupMembers = members.filter(m => !m.quit); + this.members = members; }) }, isSelf(userId) { @@ -90,6 +88,9 @@ export default { computed: { isOwner() { return this.userStore.userInfo.id == this.group.ownerId; + }, + showMembers() { + return this.members.filter(m => !m.quit && m.showNickName.includes(this.searchText)) } }, onLoad(options) { diff --git a/im-uniapp/store/chatStore.js b/im-uniapp/store/chatStore.js index 9db36b3..284b8d2 100644 --- a/im-uniapp/store/chatStore.js +++ b/im-uniapp/store/chatStore.js @@ -1,6 +1,7 @@ import { defineStore } from 'pinia'; import { MESSAGE_TYPE, MESSAGE_STATUS } from '@/common/enums.js'; import useUserStore from './userStore'; +import UNI_APP from '../.env'; let cacheChats = []; export default defineStore('chatStore', { diff --git a/im-web/src/components/chat/ChatAtBox.vue b/im-web/src/components/chat/ChatAtBox.vue index d90fc85..cbd0355 100644 --- a/im-web/src/components/chat/ChatAtBox.vue +++ b/im-web/src/components/chat/ChatAtBox.vue @@ -51,6 +51,10 @@ export default { }) } this.members.forEach((m) => { + // 只显示100条 + if (this.showMembers.length > 100) { + return; + } if (m.userId != userId && !m.quit && m.showNickName.startsWith(this.searchText)) { this.showMembers.push(m); } @@ -128,4 +132,4 @@ export default { background-color: #fff; box-shadow: var(--im-box-shadow); } - + \ No newline at end of file diff --git a/im-web/src/components/chat/ChatBox.vue b/im-web/src/components/chat/ChatBox.vue index 28afab4..654ffa6 100644 --- a/im-web/src/components/chat/ChatBox.vue +++ b/im-web/src/components/chat/ChatBox.vue @@ -41,8 +41,9 @@ -
+
@@ -67,7 +68,7 @@
- + @@ -510,7 +511,7 @@ export default { this.$http({ url: url, method: 'put' - }).then(() => {}) + }).then(() => { }) }, loadReaded(fId) { this.$http({ @@ -549,7 +550,7 @@ export default { friend.showNickName = friend.remarkNickName ? friend.remarkNickName : friend.nickName; this.$store.commit("updateChatFromFriend", friend); this.$store.commit("updateFriend", friend); - }else { + } else { this.$store.commit("updateChatFromUser", this.userInfo); } }, @@ -656,7 +657,7 @@ export default { return this.$store.getters.isFriend(this.userInfo.id); }, friend() { - return this.$store.getters.findFriend(this.userInfo.id) + return this.$store.getters.findFriend(this.userInfo.id) }, title() { let title = this.chat.showName; @@ -681,13 +682,16 @@ export default { isBanned() { return (this.chat.type == "PRIVATE" && this.userInfo.isBanned) || (this.chat.type == "GROUP" && this.group.isBanned) + }, + memberSize() { + return this.groupMembers.filter(m => !m.quit).length; } }, watch: { chat: { handler(newChat, oldChat) { if (newChat.targetId > 0 && (!oldChat || newChat.type != oldChat.type || - newChat.targetId != oldChat.targetId)) { + newChat.targetId != oldChat.targetId)) { if (this.chat.type == "GROUP") { this.loadGroup(this.chat.targetId); } else { diff --git a/im-web/src/components/chat/ChatGroupReaded.vue b/im-web/src/components/chat/ChatGroupReaded.vue index 0759f4d..a90e683 100644 --- a/im-web/src/components/chat/ChatGroupReaded.vue +++ b/im-web/src/components/chat/ChatGroupReaded.vue @@ -1,183 +1,189 @@ + \ No newline at end of file diff --git a/im-web/src/components/chat/ChatGroupSide.vue b/im-web/src/components/chat/ChatGroupSide.vue index 7c3fe36..09a4594 100644 --- a/im-web/src/components/chat/ChatGroupSide.vue +++ b/im-web/src/components/chat/ChatGroupSide.vue @@ -6,20 +6,22 @@
-
-
-
- + +
+
+
+ +
+
邀请
+ +
+
+
-
邀请
- -
-
-
-
+ @@ -62,7 +64,8 @@ export default { return { searchText: "", editing: false, - showAddGroupMember: false + showAddGroupMember: false, + showMaxIdx: 50 } }, props: { @@ -113,7 +116,15 @@ export default { }); }) }, - + onScroll(e) { + const scrollbar = e.target; + // 滚到底部 + if (scrollbar.scrollTop + scrollbar.clientHeight >= scrollbar.scrollHeight - 30) { + if (this.showMaxIdx < this.showMembers.length) { + this.showMaxIdx += 30; + } + } + } }, computed: { ownerName() { @@ -122,8 +133,17 @@ export default { }, isOwner() { return this.group.ownerId == this.$store.state.userStore.userInfo.id; + }, + showMembers() { + return this.groupMembers.filter((m) => !m.quit && m.showNickName.includes(this.searchText)) + }, + scrollHeight() { + return Math.min(400, 80 + this.showMembers.length / 5 * 80); } - + }, + mounted() { + let scrollWrap = this.$refs.scrollbar.$el.querySelector('.el-scrollbar__wrap'); + scrollWrap.addEventListener('scroll', this.onScroll); } } diff --git a/im-web/src/components/common/VirtualScroller.vue b/im-web/src/components/common/VirtualScroller.vue new file mode 100644 index 0000000..2fac4cd --- /dev/null +++ b/im-web/src/components/common/VirtualScroller.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/im-web/src/components/group/GroupMemberSelector.vue b/im-web/src/components/group/GroupMemberSelector.vue index a31571a..dc2f941 100644 --- a/im-web/src/components/group/GroupMemberSelector.vue +++ b/im-web/src/components/group/GroupMemberSelector.vue @@ -5,15 +5,14 @@ - -
- - + +
@@ -33,6 +32,7 @@