From 8fd21da555d581afe9ebf2e19fb243976d37ca78 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 27 Apr 2026 19:59:56 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(im):=20TIP=5FTEXT=20?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=8F=90=E7=A4=BA=E4=B8=8D=E5=86=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E7=A9=BA=E7=99=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 群解散 / 退群 / 踢人 等系统提示后端发的是裸字符串,之前按 TextMessage JSON 解析 → 主聊天窗显示空行、会话列表摘要变空。 - message.ts:新增 resolveTipText helper,兼容裸字符串 + {"content":"..."} - MessageItem / conversationStore.resolveLastContent 把 TIP_TEXT 从 TEXT 分支拆出来,统一走 resolveTipText(TEXT 仍按 JSON 解析,没有裸字符串可能) Co-Authored-By: Claude Opus 4.7 (1M context) --- src/assets/audio/im-message-tip.mp3 | Bin 0 -> 13059 bytes .../components/ChatGroupMember.vue | 87 ++++++ .../conversation/components/ChatGroupSide.vue | 275 ++++++++++++++++++ .../conversation/components/ChatPanel.vue | 42 +++ .../components/ChatPrivateSide.vue | 110 +++++++ .../components/message/MessageHistory.vue | 162 +++++++++++ .../components/message/MessageReadStatus.vue | 125 ++++++++ src/views/im/home/pages/friend/FriendPage.vue | 22 ++ .../pages/friend/components/FriendItem.vue | 129 ++++++++ src/views/im/home/pages/group/GroupPage.vue | 22 ++ .../group/components/AddGroupMemberDialog.vue | 192 ++++++++++++ .../group/components/CreateGroupDialog.vue | 174 +++++++++++ .../home/pages/group/components/GroupItem.vue | 96 ++++++ .../group/components/GroupMemberGrid.vue | 52 ++++ .../group/components/GroupMemberItem.vue | 87 ++++++ .../group/components/GroupMemberSelector.vue | 213 ++++++++++++++ src/views/im/manager/index.vue | 0 src/views/im/utils/index.ts | 30 ++ 18 files changed, 1818 insertions(+) create mode 100644 src/assets/audio/im-message-tip.mp3 create mode 100644 src/views/im/home/pages/conversation/components/ChatGroupMember.vue create mode 100644 src/views/im/home/pages/conversation/components/ChatGroupSide.vue create mode 100644 src/views/im/home/pages/conversation/components/ChatPanel.vue create mode 100644 src/views/im/home/pages/conversation/components/ChatPrivateSide.vue create mode 100644 src/views/im/home/pages/conversation/components/message/MessageHistory.vue create mode 100644 src/views/im/home/pages/conversation/components/message/MessageReadStatus.vue create mode 100644 src/views/im/home/pages/friend/FriendPage.vue create mode 100644 src/views/im/home/pages/friend/components/FriendItem.vue create mode 100644 src/views/im/home/pages/group/GroupPage.vue create mode 100644 src/views/im/home/pages/group/components/AddGroupMemberDialog.vue create mode 100644 src/views/im/home/pages/group/components/CreateGroupDialog.vue create mode 100644 src/views/im/home/pages/group/components/GroupItem.vue create mode 100644 src/views/im/home/pages/group/components/GroupMemberGrid.vue create mode 100644 src/views/im/home/pages/group/components/GroupMemberItem.vue create mode 100644 src/views/im/home/pages/group/components/GroupMemberSelector.vue create mode 100644 src/views/im/manager/index.vue create mode 100644 src/views/im/utils/index.ts diff --git a/src/assets/audio/im-message-tip.mp3 b/src/assets/audio/im-message-tip.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..5f317dcd466c5430bb0b7a7c1bee9ea8e3f6c430 GIT binary patch literal 13059 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%0D#7~VnCN+4A3wP^3G94Y}5tr zb#cajtFme7R{byRPu%^jf@LD|+5@V!(R<+6P-@bA91EqfrH@R(c`?e}J*TLpG w*jxwy + +
+ +
+ {{ member.showNickName }} +
+
+ + + + + diff --git a/src/views/im/home/pages/conversation/components/ChatGroupSide.vue b/src/views/im/home/pages/conversation/components/ChatGroupSide.vue new file mode 100644 index 000000000..4e5426b44 --- /dev/null +++ b/src/views/im/home/pages/conversation/components/ChatGroupSide.vue @@ -0,0 +1,275 @@ + + + + + diff --git a/src/views/im/home/pages/conversation/components/ChatPanel.vue b/src/views/im/home/pages/conversation/components/ChatPanel.vue new file mode 100644 index 000000000..a07bf0c53 --- /dev/null +++ b/src/views/im/home/pages/conversation/components/ChatPanel.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/src/views/im/home/pages/conversation/components/ChatPrivateSide.vue b/src/views/im/home/pages/conversation/components/ChatPrivateSide.vue new file mode 100644 index 000000000..f7456ca8b --- /dev/null +++ b/src/views/im/home/pages/conversation/components/ChatPrivateSide.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/views/im/home/pages/conversation/components/message/MessageHistory.vue b/src/views/im/home/pages/conversation/components/message/MessageHistory.vue new file mode 100644 index 000000000..d4b97111f --- /dev/null +++ b/src/views/im/home/pages/conversation/components/message/MessageHistory.vue @@ -0,0 +1,162 @@ + + + + + diff --git a/src/views/im/home/pages/conversation/components/message/MessageReadStatus.vue b/src/views/im/home/pages/conversation/components/message/MessageReadStatus.vue new file mode 100644 index 000000000..36f39d299 --- /dev/null +++ b/src/views/im/home/pages/conversation/components/message/MessageReadStatus.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/src/views/im/home/pages/friend/FriendPage.vue b/src/views/im/home/pages/friend/FriendPage.vue new file mode 100644 index 000000000..0befbe68b --- /dev/null +++ b/src/views/im/home/pages/friend/FriendPage.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/views/im/home/pages/friend/components/FriendItem.vue b/src/views/im/home/pages/friend/components/FriendItem.vue new file mode 100644 index 000000000..279302f7a --- /dev/null +++ b/src/views/im/home/pages/friend/components/FriendItem.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/src/views/im/home/pages/group/GroupPage.vue b/src/views/im/home/pages/group/GroupPage.vue new file mode 100644 index 000000000..539f731a5 --- /dev/null +++ b/src/views/im/home/pages/group/GroupPage.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/views/im/home/pages/group/components/AddGroupMemberDialog.vue b/src/views/im/home/pages/group/components/AddGroupMemberDialog.vue new file mode 100644 index 000000000..f018bd7e2 --- /dev/null +++ b/src/views/im/home/pages/group/components/AddGroupMemberDialog.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/src/views/im/home/pages/group/components/CreateGroupDialog.vue b/src/views/im/home/pages/group/components/CreateGroupDialog.vue new file mode 100644 index 000000000..9d9135ab2 --- /dev/null +++ b/src/views/im/home/pages/group/components/CreateGroupDialog.vue @@ -0,0 +1,174 @@ + + + diff --git a/src/views/im/home/pages/group/components/GroupItem.vue b/src/views/im/home/pages/group/components/GroupItem.vue new file mode 100644 index 000000000..be8ba9bb2 --- /dev/null +++ b/src/views/im/home/pages/group/components/GroupItem.vue @@ -0,0 +1,96 @@ + + + + + diff --git a/src/views/im/home/pages/group/components/GroupMemberGrid.vue b/src/views/im/home/pages/group/components/GroupMemberGrid.vue new file mode 100644 index 000000000..ed759a165 --- /dev/null +++ b/src/views/im/home/pages/group/components/GroupMemberGrid.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/src/views/im/home/pages/group/components/GroupMemberItem.vue b/src/views/im/home/pages/group/components/GroupMemberItem.vue new file mode 100644 index 000000000..049078281 --- /dev/null +++ b/src/views/im/home/pages/group/components/GroupMemberItem.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/src/views/im/home/pages/group/components/GroupMemberSelector.vue b/src/views/im/home/pages/group/components/GroupMemberSelector.vue new file mode 100644 index 000000000..02002d352 --- /dev/null +++ b/src/views/im/home/pages/group/components/GroupMemberSelector.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/src/views/im/manager/index.vue b/src/views/im/manager/index.vue new file mode 100644 index 000000000..e69de29bb diff --git a/src/views/im/utils/index.ts b/src/views/im/utils/index.ts new file mode 100644 index 000000000..e8d18a95c --- /dev/null +++ b/src/views/im/utils/index.ts @@ -0,0 +1,30 @@ +/** 生成客户端消息 ID(时间戳 + UUID) */ +export const generateClientMessageId = (): string => { + const timestamp = Date.now().toString() + const randomPart = 'xxxx-xxxx-4xxx-yxxx-xxxx'.replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0 + const v = c === 'x' ? r : (r & 0x3) | 0x8 + return v.toString(16) + }) + return `${timestamp}-${randomPart}` +} + +/** 生成存储 key(对齐 boxim key 命名 chats-{userId}) */ +export const buildMetaKey = (userId: string): string => { + return `chats-${userId}` +} + +/** 解析文本消息 content JSON */ +export const parseTextContent = (content: string): string => { + try { + const parsed = JSON.parse(content) + return parsed.content || '' + } catch { + return content + } +} + +/** 序列化文本消息 content JSON */ +export const serializeTextContent = (text: string): string => { + return JSON.stringify({ content: text }) +}