From f2ffda5e7a3260f2c3b026e43272c4e626db2455 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Thu, 16 Oct 2025 00:12:29 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E7=BB=86=E8=8A=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat-message-item/chat-message-item.vue | 5 ++++- im-uniapp/pages/chat/chat-box.vue | 12 +++++++++++- im-web/src/components/chat/ChatBox.vue | 6 ++++++ 3 files changed, 21 insertions(+), 2 deletions(-) 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 5b1a43d..f35dd7b 100644 --- a/im-uniapp/components/chat-message-item/chat-message-item.vue +++ b/im-uniapp/components/chat-message-item/chat-message-item.vue @@ -65,7 +65,7 @@ {{ msgInfo.content }} - + { // 更新消息 + tmpMessage = JSON.parse(JSON.stringify(tmpMessage)); tmpMessage.id = m.id; tmpMessage.status = m.status; this.chatStore.updateMessage(tmpMessage, chat); @@ -194,7 +195,10 @@ export default { // 滚动到底部 this.scrollToBottom(); this.isReceipt = false; - + }).catch(() => { + tmpMessage = JSON.parse(JSON.stringify(tmpMessage)); + tmpMessage.status = this.$enums.MESSAGE_STATUS.FAILED; + this.chatStore.updateMessage(tmpMessage, chat); }) }, onRtCall(msgInfo) { @@ -474,6 +478,9 @@ export default { msgInfo.status = m.status; this.isReceipt = false; this.chatStore.updateMessage(msgInfo, file.chat); + }).catch(() => { + msgInfo.status = this.$enums.MESSAGE_STATUS.FAILED; + this.chatStore.updateMessage(msgInfo, file.chat); }) }, onUploadImageFail(file, err) { @@ -527,6 +534,9 @@ export default { msgInfo.status = m.status; this.isReceipt = false; this.chatStore.updateMessage(msgInfo, file.chat); + }).catch(() => { + msgInfo.status = this.$enums.MESSAGE_STATUS.FAILED; + this.chatStore.updateMessage(msgInfo, file.chat); }) }, onUploadFileFail(file, res) { diff --git a/im-web/src/components/chat/ChatBox.vue b/im-web/src/components/chat/ChatBox.vue index 69152a1..3318a81 100644 --- a/im-web/src/components/chat/ChatBox.vue +++ b/im-web/src/components/chat/ChatBox.vue @@ -164,6 +164,9 @@ export default { msgInfo.status = m.status; this.isReceipt = false; this.chatStore.updateMessage(msgInfo, file.chat); + }).catch(() => { + msgInfo.status = this.$enums.MESSAGE_STATUS.FAILED; + this.chatStore.updateMessage(msgInfo, file.chat); }) }, onImageFail(e, file) { @@ -227,6 +230,9 @@ export default { this.isReceipt = false; this.refreshPlaceHolder(); this.chatStore.updateMessage(msgInfo, file.chat); + }).catch(() => { + msgInfo.status = this.$enums.MESSAGE_STATUS.FAILED; + this.chatStore.updateMessage(msgInfo, file.chat); }) }, onFileFail(e, file) { From 13d496741d2e807c2cc4e00d5b8cfe3e7c622e13 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Thu, 16 Oct 2025 00:15:21 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E7=BB=86=E8=8A=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat-message-item/chat-message-item.vue | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) 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 f35dd7b..dbcecc3 100644 --- a/im-uniapp/components/chat-message-item/chat-message-item.vue +++ b/im-uniapp/components/chat-message-item/chat-message-item.vue @@ -11,7 +11,7 @@ :name="showName" size="small"> - {{ showName }} + {{ showName }} @@ -294,10 +294,17 @@ export default { .top { display: flex; flex-wrap: nowrap; - color: $im-text-color-lighter; - font-size: $im-font-size-smaller; - line-height: $im-font-size-smaller; - height: $im-font-size-smaller; + align-items: center; + + .name { + color: $im-text-color-lighter; + font-size: $im-font-size-smaller; + line-height: $im-font-size-smaller; + height: $im-font-size-smaller; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } } .bottom { From 8f355d5a7388f0606098f8deb1df398c2e228606 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Mon, 20 Oct 2025 16:05:59 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=90=8D=E9=95=BF?= =?UTF-8?q?=E5=BA=A6=E9=99=90=E5=88=B6128=E5=AD=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/bx/implatform/contant/Constant.java | 5 +++++ .../bx/implatform/service/impl/FileServiceImpl.java | 10 ++++++++++ 2 files changed, 15 insertions(+) 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 3884cd7..d255ba3 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 @@ -15,6 +15,11 @@ public final class Constant { */ public static final Long MAX_FILE_SIZE = 20 * 1024 * 1024L; + /** + * 最大文件名长度 + */ + public static final Long MAX_FILE_NAME_LENGTH = 128L; + /** * 大群人数上限 */ diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/FileServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/FileServiceImpl.java index 761f2dc..9eb4ce5 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/FileServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/FileServiceImpl.java @@ -60,6 +60,8 @@ public class FileServiceImpl extends ServiceImpl imple public String uploadFile(MultipartFile file) { try { Long userId = SessionContext.getSession().getUserId(); + // 文件名长度校验 + checkFileNameLength(file); // 大小校验 if (file.getSize() > Constant.MAX_FILE_SIZE) { throw new GlobalException(ResultCode.PROGRAM_ERROR, "文件大小不能超过20M"); @@ -95,6 +97,8 @@ public class FileServiceImpl extends ServiceImpl imple public UploadImageVO uploadImage(MultipartFile file, Boolean isPermanent,Long thumbSize) { try { Long userId = SessionContext.getSession().getUserId(); + // 文件名长度校验 + checkFileNameLength(file); // 大小校验 if (file.getSize() > Constant.MAX_IMAGE_SIZE) { throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片大小不能超过20M"); @@ -170,6 +174,7 @@ public class FileServiceImpl extends ServiceImpl imple LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(FileInfo::getMd5, md5); wrapper.eq(FileInfo::getFileType, fileType); + wrapper.last("limit 1"); return getOne(wrapper); } @@ -199,4 +204,9 @@ public class FileServiceImpl extends ServiceImpl imple this.save(fileInfo); } + private void checkFileNameLength(MultipartFile file){ + if(file.getOriginalFilename().length() > Constant.MAX_FILE_NAME_LENGTH){ + throw new GlobalException("文件名长度不能超过" + Constant.MAX_FILE_NAME_LENGTH); + } + } } From 0457e706ee43a0fdca59bf5cd7d555b5113f87b3 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Mon, 20 Oct 2025 16:12:11 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20=E5=90=8C=E6=97=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B1=E8=B4=A5=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-uniapp/pages/chat/chat-box.vue | 13 +++++++++++-- im-web/src/components/chat/ChatBox.vue | 27 +++++++++++++++++--------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/im-uniapp/pages/chat/chat-box.vue b/im-uniapp/pages/chat/chat-box.vue index 7c0a7c6..296a497 100644 --- a/im-uniapp/pages/chat/chat-box.vue +++ b/im-uniapp/pages/chat/chat-box.vue @@ -152,7 +152,8 @@ export default { isInBottom: true, // 滚动条是否在底部 newMessageSize: 0, // 滚动条不在底部时新的消息数量 scrollTop: 0, // 用于ios h5定位滚动条 - scrollViewHeight: 0 // 滚动条总长度 + scrollViewHeight: 0, // 滚动条总长度 + maxTmpId: 0 // 最后生成的临时id } }, methods: { @@ -983,7 +984,13 @@ export default { }, generateId() { // 生成临时id - return String(new Date().getTime()) + String(Math.floor(Math.random() * 1000)); + const id = String(new Date().getTime()) + String(Math.floor(Math.random() * 1000)); + // 必须保证id是递增 + if (this.maxTmpId > id) { + return this.generateId(); + } + this.maxTmpId = id; + return id; } }, computed: { @@ -1108,6 +1115,8 @@ export default { // 清空底部标志 this.isInBottom = true; this.newMessageSize = 0; + // 清空消息临时id + this.maxTmpId = 0; // 监听键盘高度 this.listenKeyBoard(); // 计算聊天窗口高度 diff --git a/im-web/src/components/chat/ChatBox.vue b/im-web/src/components/chat/ChatBox.vue index 3318a81..c6e2322 100644 --- a/im-web/src/components/chat/ChatBox.vue +++ b/im-web/src/components/chat/ChatBox.vue @@ -132,7 +132,8 @@ export default { reqQueue: [], // 等待发送的请求队列 isSending: false, // 是否正在发消息 isInBottom: false, // 滚动条是否在底部 - newMessageSize: 0 // 滚动条不在底部时新的消息数量 + newMessageSize: 0, // 滚动条不在底部时新的消息数量 + maxTmpId: 0 // 最后生成的临时ID } }, methods: { @@ -573,7 +574,7 @@ export default { this.$http({ url: url, method: 'put' - }).then(() => { }) + }).then(() => {}) this.chatStore.resetUnreadCount(this.chat) } }, @@ -724,25 +725,31 @@ export default { getImageSize(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); - reader.onload = function (event) { + reader.onload = function(event) { const img = new Image(); - img.onload = function () { + img.onload = function() { resolve({ width: img.width, height: img.height }); }; - img.onerror = function () { + img.onerror = function() { reject(new Error('无法加载图片')); }; img.src = event.target.result; }; - reader.onerror = function () { + reader.onerror = function() { reject(new Error('无法读取文件')); }; reader.readAsDataURL(file); }); }, generateId() { - // 生成临时id - return String(new Date().getTime()) + String(Math.floor(Math.random() * 1000)); + // 生成临时id + const id = String(new Date().getTime()) + String(Math.floor(Math.random() * 1000)); + // 必须保证id是递增 + if (this.maxTmpId > id) { + return this.generateId(); + } + this.maxTmpId = id; + return id; } }, computed: { @@ -799,7 +806,7 @@ export default { chat: { handler(newChat, oldChat) { if (newChat.targetId > 0 && (!oldChat || newChat.type != oldChat.type || - newChat.targetId != oldChat.targetId)) { + newChat.targetId != oldChat.targetId)) { this.userInfo = {} this.group = {}; this.groupMembers = []; @@ -822,6 +829,8 @@ export default { this.resetEditor(); // 复位回执消息 this.isReceipt = false; + // 清空消息临时id + this.maxTmpId = 0; // 更新placeholder this.refreshPlaceHolder(); } From c328524c9f08300328b0c6ea2efc8019f858f2b1 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Sun, 2 Nov 2025 17:08:32 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20=E6=B6=88=E6=81=AF=E9=80=81=E8=BE=BE?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=BC=82=E5=B8=B8=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../implatform/listener/PrivateMessageListener.java | 12 ++++++++---- .../service/impl/PrivateMessageServiceImpl.java | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java index d75ab86..ba61cd2 100644 --- a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java +++ b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java @@ -26,19 +26,23 @@ public class PrivateMessageListener implements MessageListener @Lazy @Autowired private PrivateMessageService privateMessageService; + @Override public void process(List> results) { Set messageIds = new HashSet<>(); - for(IMSendResult result : results){ + for (IMSendResult result : results) { PrivateMessageVO messageInfo = result.getData(); // 更新消息状态,这里只处理成功消息,失败的消息继续保持未读状态 if (result.getCode().equals(IMSendCode.SUCCESS.code()) && !Objects.isNull(messageInfo.getId())) { - messageIds.add(messageInfo.getId()); - log.info("消息送达,消息id:{},发送者:{},接收者:{},终端:{}", messageInfo.getId(), result.getSender().getId(), result.getReceiver().getId(), result.getReceiver().getTerminal()); + if (result.getReceiver().getId().equals(messageInfo.getRecvId())) { + messageIds.add(messageInfo.getId()); + log.info("消息送达,消息id:{},发送者:{},接收者:{},终端:{}", messageInfo.getId(), + result.getSender().getId(), result.getReceiver().getId(), result.getReceiver().getTerminal()); + } } } // 批量修改状态 - if(CollUtil.isNotEmpty(messageIds)){ + if (CollUtil.isNotEmpty(messageIds)) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.lambda().in(PrivateMessage::getId, messageIds) .eq(PrivateMessage::getStatus, MessageStatus.PENDING.code()) diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java index 24c4972..3401f8a 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java @@ -189,9 +189,9 @@ public class PrivateMessageServiceImpl extends ServiceImpl messages = this.list(wrapper); // 更新消息为送达状态 - List messageIds = - messages.stream().filter(m -> m.getStatus().equals(MessageStatus.PENDING.code())).map(PrivateMessage::getId) - .collect(Collectors.toList()); + List messageIds = messages.stream().filter(m -> m.getRecvId().equals(session.getUserId())) + .filter(m -> m.getStatus().equals(MessageStatus.PENDING.code())).map(PrivateMessage::getId) + .collect(Collectors.toList()); if (!messageIds.isEmpty()) { LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate(); updateWrapper.in(PrivateMessage::getId, messageIds); From aa18f59f4c7f6a92305a839b2584cbb1128fe278 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Sun, 2 Nov 2025 17:11:35 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20ios=E9=83=A8=E5=88=86=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=87=BA=E7=8E=B0=E7=99=BD=E5=B1=8F=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-uniapp/pages/chat/chat-box.vue | 32 ++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/im-uniapp/pages/chat/chat-box.vue b/im-uniapp/pages/chat/chat-box.vue index 296a497..ff3b7e7 100644 --- a/im-uniapp/pages/chat/chat-box.vue +++ b/im-uniapp/pages/chat/chat-box.vue @@ -642,13 +642,21 @@ export default { }); }, onClickToBottom() { - this.scrollToBottom(); - // 有些设备滚到底部时会莫名触发滚动到顶部的事件 - // 所以这里延迟100s保证能准确设置底部标志 + /** + * 有些ios设备在点击回到底部后页面会卡住,原因不详 + * 解决方式: 延迟300ms再滚动 + */ setTimeout(() => { - this.isInBottom = true; - this.newMessageSize = 0; - }, 100) + this.scrollToBottom(); + /** + * 有些设备滚到底部时会莫名触发滚动到顶部的事件 + * 解决方式: 延迟100ms保证能准确设置底部标志 + */ + setTimeout(() => { + this.isInBottom = true; + this.newMessageSize = 0; + }, 100) + }, 300) }, onScroll(e) { // 记录当前滚动条高度 @@ -656,16 +664,14 @@ export default { }, onScrollToTop() { if (this.showMinIdx > 0) { - // #ifndef H5 - // 防止滚动条定格在顶部,不能一直往上滚,app和小程序采用scroll-into-view定位 - this.scrollToMsgIdx(this.showMinIdx); - // #endif - // #ifdef H5 - // 防止滚动条定格在顶部,不能一直往上滚,h5采用scroll-top定位 + // 防止滚动条定格在顶部,不能一直往上滚 if (uni.getSystemInfoSync().platform == 'ios') { + // ios采用scroll-top定位,否则可能会出现白屏 this.holdingScrollBar(this.scrollViewHeight); + } else { + // 安卓采用scroll-into-view定位 + this.scrollToMsgIdx(this.showMinIdx); } - // #endif // 多展示20条信息 this.showMinIdx = this.showMinIdx > 20 ? this.showMinIdx - 20 : 0; }