From 2cbec901e1a1e345786ef6bd436f31bec0d1efef Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 18 Jun 2026 05:53:25 -0700 Subject: [PATCH] =?UTF-8?q?feat(im)=EF=BC=9A=E8=A7=84=E8=8C=83=20Vben=20IM?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E7=9B=AE=E5=BD=95=E5=B9=B6=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E8=81=8A=E5=A4=A9=E7=AB=AF=E8=BF=81=E7=A7=BB=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 文件命名与目录整理: - IM home/manager 组件文件统一 PascalCase → kebab-case,并新增各级 components/index.ts barrel 导出 - manager 选择器按业务模块就近收敛到频道、素材、群组目录,删除根 components 下的重复实现 - UserMultiSelect 改为复用 system/user/components/UserSelect,并补充多选与 getUserList 回显能力 - 合并 statistics 子组件导出,MessageContentPreview 调整为 content-preview 问题修复: - 群聊发送按钮由 Element Plus split-button 写法改为 antd DropdownButton,恢复「发送回执消息」入口 - 修复 scoped 下暗色模式选择器塌缩导致整页发红的问题 - 修复会话「+」菜单图标与文字折行问题 - 修复推荐名片、转发、添加好友弹窗冒出多余 antd 默认底栏的问题 代码规范: - 清理 IM 模块类型别名、注释和工具方法写法,保持 Vben 规范 - constants.ts 内容类型判定集合由数组改为 Set - 优化 message/image/pull 等工具函数的 lint 写法 --- apps/web-antd/src/api/system/user/index.ts | 7 + .../card/{CardBubble.vue => card-bubble.vue} | 2 +- ...{CardLineLabel.vue => card-line-label.vue} | 0 .../views/im/home/components/card/index.ts | 2 + .../{ContextMenu.vue => context-menu.vue} | 0 ...endAddDialog.vue => friend-add-dialog.vue} | 10 +- .../{FriendItem.vue => friend-item.vue} | 2 +- .../views/im/home/components/friend/index.ts | 2 + ...tDialog.vue => group-admin-set-dialog.vue} | 4 +- .../{GroupAvatar.vue => group-avatar.vue} | 2 +- ...eateDialog.vue => group-create-dialog.vue} | 2 +- ...{GroupInfoCard.vue => group-info-card.vue} | 2 +- .../group/{GroupInfo.vue => group-info.vue} | 6 +- .../group/{GroupItem.vue => group-item.vue} | 2 +- ...Dialog.vue => group-member-add-dialog.vue} | 4 +- ...upMemberGrid.vue => group-member-grid.vue} | 4 +- ...upMemberItem.vue => group-member-item.vue} | 4 +- ...log.vue => group-member-remove-dialog.vue} | 4 +- .../{GroupMember.vue => group-member.vue} | 2 +- ...ialog.vue => group-mute-member-dialog.vue} | 0 ...og.vue => group-owner-transfer-dialog.vue} | 4 +- ...alog.vue => group-request-list-dialog.vue} | 3 +- .../views/im/home/components/group/index.ts | 15 + .../src/views/im/home/components/index.ts | 4 + .../{PagedScroller.vue => paged-scroller.vue} | 1 + ...anel.vue => conversation-picker-panel.vue} | 4 +- ...ickerPanel.vue => friend-picker-panel.vue} | 4 +- ...anel.vue => group-member-picker-panel.vue} | 9 +- .../views/im/home/components/picker/index.ts | 3 + ...ResizableAside.vue => resizable-aside.vue} | 0 .../src/views/im/home/components/rtc/index.ts | 8 + ...llContainer.vue => rtc-call-container.vue} | 10 +- ...CallIncoming.vue => rtc-call-incoming.vue} | 2 +- ...CallInviting.vue => rtc-call-inviting.vue} | 14 +- ....vue => rtc-call-member-picker-dialog.vue} | 4 +- ...Tile.vue => rtc-call-participant-tile.vue} | 2 +- ...tcCallRunning.vue => rtc-call-running.vue} | 24 +- ...llBanner.vue => rtc-group-call-banner.vue} | 2 +- .../components/{ToolBar.vue => tool-bar.vue} | 2 +- .../views/im/home/components/user/index.ts | 5 + ...rdDialog.vue => recommend-card-dialog.vue} | 9 +- .../user/{UserAvatar.vue => user-avatar.vue} | 9 +- .../{UserInfoCard.vue => user-info-card.vue} | 2 +- .../user/{UserInfo.vue => user-info.vue} | 6 +- .../im/home/composables/useFriendBuckets.ts | 13 +- .../im/home/composables/useMessagePuller.ts | 8 +- .../im/home/composables/useMessageSender.ts | 2 +- apps/web-antd/src/views/im/home/index.vue | 57 +++- .../{FriendList.vue => friend-list.vue} | 2 +- ...stDetail.vue => friend-request-detail.vue} | 4 +- ...equestList.vue => friend-request-list.vue} | 2 +- .../{GroupDetail.vue => group-detail.vue} | 2 +- .../contact/{GroupList.vue => group-list.vue} | 2 +- .../src/views/im/home/pages/contact/index.vue | 14 +- ...upSide.vue => conversation-group-side.vue} | 19 +- ...ersationItem.vue => conversation-item.vue} | 4 +- ...Side.vue => conversation-private-side.vue} | 4 +- .../components/conversation/index.ts | 3 + .../pages/conversation/components/index.ts | 3 + .../input/{FacePicker.vue => face-picker.vue} | 0 .../conversation/components/input/index.ts | 5 + .../{MentionPicker.vue => mention-picker.vue} | 2 +- .../{MessageInput.vue => message-input.vue} | 25 +- ...ctBar.vue => message-multi-select-bar.vue} | 0 .../{VoiceRecorder.vue => voice-recorder.vue} | 0 .../components/message/forward/index.ts | 2 + ...dDialog.vue => message-forward-dialog.vue} | 7 +- ...og.vue => message-merge-detail-dialog.vue} | 5 +- ...edMessage.vue => group-pinned-message.vue} | 0 ...tPending.vue => group-request-pending.vue} | 2 +- .../conversation/components/message/index.ts | 10 + ...MaterialBubble.vue => material-bubble.vue} | 0 .../{MessageBubble.vue => message-bubble.vue} | 9 +- ...MessageHistory.vue => message-history.vue} | 9 +- .../{MessageItem.vue => message-item.vue} | 12 +- .../{MessagePanel.vue => message-panel.vue} | 30 +- ...ReadStatus.vue => message-read-status.vue} | 4 +- .../{ReplyPreview.vue => reply-preview.vue} | 2 +- .../{TipSegments.vue => tip-segments.vue} | 0 .../im/home/pages/conversation/index.vue | 21 +- .../src/views/im/home/store/uiStore.ts | 2 +- .../manager/channel/list/components/index.ts | 1 + .../list/components/select.vue} | 0 .../channel/material/components/index.ts | 1 + .../material/components/select.vue} | 0 .../views/im/manager/channel/material/data.ts | 2 +- .../channel/message/modules/send-form.vue | 9 +- .../im/manager/components/GroupSelect.vue | 74 ----- .../im/manager/components/UserMultiSelect.vue | 107 ------- .../src/views/im/manager/friend/data.ts | 2 +- .../im/manager/group/components/index.ts | 2 + .../group/components/select-dialog.vue | 271 ++++++++++++++++++ .../im/manager/group/components/select.vue | 129 +++++++++ .../src/views/im/manager/group/data.ts | 4 +- ...ContentPreview.vue => content-preview.vue} | 2 +- .../src/views/im/manager/message/data.ts | 4 +- .../views/im/manager/message/group/index.vue | 2 +- .../manager/message/group/modules/detail.vue | 2 +- .../src/views/im/manager/message/index.ts | 1 + .../im/manager/message/private/index.vue | 2 +- .../message/private/modules/detail.vue | 2 +- .../web-antd/src/views/im/manager/rtc/data.ts | 2 +- ...butionChart.vue => distribution-chart.vue} | 0 .../im/manager/statistics/components/index.ts | 3 + .../{OverviewCards.vue => overview-cards.vue} | 0 .../{TrendChart.vue => trend-chart.vue} | 0 .../src/views/im/manager/statistics/index.vue | 8 +- apps/web-antd/src/views/im/utils/constants.ts | 32 +-- apps/web-antd/src/views/im/utils/image.ts | 6 +- apps/web-antd/src/views/im/utils/message.ts | 8 +- apps/web-antd/src/views/im/utils/pull.ts | 2 +- .../views/system/user/components/select.vue | 130 ++++++--- 112 files changed, 862 insertions(+), 439 deletions(-) rename apps/web-antd/src/views/im/home/components/card/{CardBubble.vue => card-bubble.vue} (97%) rename apps/web-antd/src/views/im/home/components/card/{CardLineLabel.vue => card-line-label.vue} (100%) create mode 100644 apps/web-antd/src/views/im/home/components/card/index.ts rename apps/web-antd/src/views/im/home/components/{ContextMenu.vue => context-menu.vue} (100%) rename apps/web-antd/src/views/im/home/components/friend/{FriendAddDialog.vue => friend-add-dialog.vue} (98%) rename apps/web-antd/src/views/im/home/components/friend/{FriendItem.vue => friend-item.vue} (97%) create mode 100644 apps/web-antd/src/views/im/home/components/friend/index.ts rename apps/web-antd/src/views/im/home/components/group/{GroupAdminSetDialog.vue => group-admin-set-dialog.vue} (96%) rename apps/web-antd/src/views/im/home/components/group/{GroupAvatar.vue => group-avatar.vue} (98%) rename apps/web-antd/src/views/im/home/components/group/{GroupCreateDialog.vue => group-create-dialog.vue} (98%) rename apps/web-antd/src/views/im/home/components/group/{GroupInfoCard.vue => group-info-card.vue} (98%) rename apps/web-antd/src/views/im/home/components/group/{GroupInfo.vue => group-info.vue} (97%) rename apps/web-antd/src/views/im/home/components/group/{GroupItem.vue => group-item.vue} (95%) rename apps/web-antd/src/views/im/home/components/group/{GroupMemberAddDialog.vue => group-member-add-dialog.vue} (97%) rename apps/web-antd/src/views/im/home/components/group/{GroupMemberGrid.vue => group-member-grid.vue} (93%) rename apps/web-antd/src/views/im/home/components/group/{GroupMemberItem.vue => group-member-item.vue} (95%) rename apps/web-antd/src/views/im/home/components/group/{GroupMemberRemoveDialog.vue => group-member-remove-dialog.vue} (95%) rename apps/web-antd/src/views/im/home/components/group/{GroupMember.vue => group-member.vue} (97%) rename apps/web-antd/src/views/im/home/components/group/{GroupMuteMemberDialog.vue => group-mute-member-dialog.vue} (100%) rename apps/web-antd/src/views/im/home/components/group/{GroupOwnerTransferDialog.vue => group-owner-transfer-dialog.vue} (95%) rename apps/web-antd/src/views/im/home/components/group/{GroupRequestListDialog.vue => group-request-list-dialog.vue} (99%) create mode 100644 apps/web-antd/src/views/im/home/components/group/index.ts create mode 100644 apps/web-antd/src/views/im/home/components/index.ts rename apps/web-antd/src/views/im/home/components/{PagedScroller.vue => paged-scroller.vue} (99%) rename apps/web-antd/src/views/im/home/components/picker/{ConversationPickerPanel.vue => conversation-picker-panel.vue} (99%) rename apps/web-antd/src/views/im/home/components/picker/{FriendPickerPanel.vue => friend-picker-panel.vue} (98%) rename apps/web-antd/src/views/im/home/components/picker/{GroupMemberPickerPanel.vue => group-member-picker-panel.vue} (96%) create mode 100644 apps/web-antd/src/views/im/home/components/picker/index.ts rename apps/web-antd/src/views/im/home/components/{ResizableAside.vue => resizable-aside.vue} (100%) create mode 100644 apps/web-antd/src/views/im/home/components/rtc/index.ts rename apps/web-antd/src/views/im/home/components/rtc/{RtcCallContainer.vue => rtc-call-container.vue} (98%) rename apps/web-antd/src/views/im/home/components/rtc/{RtcCallIncoming.vue => rtc-call-incoming.vue} (98%) rename apps/web-antd/src/views/im/home/components/rtc/{RtcCallInviting.vue => rtc-call-inviting.vue} (95%) rename apps/web-antd/src/views/im/home/components/rtc/{RtcCallMemberPickerDialog.vue => rtc-call-member-picker-dialog.vue} (96%) rename apps/web-antd/src/views/im/home/components/rtc/{RtcCallParticipantTile.vue => rtc-call-participant-tile.vue} (98%) rename apps/web-antd/src/views/im/home/components/rtc/{RtcCallRunning.vue => rtc-call-running.vue} (96%) rename apps/web-antd/src/views/im/home/components/rtc/{RtcGroupCallBanner.vue => rtc-group-call-banner.vue} (99%) rename apps/web-antd/src/views/im/home/components/{ToolBar.vue => tool-bar.vue} (98%) create mode 100644 apps/web-antd/src/views/im/home/components/user/index.ts rename apps/web-antd/src/views/im/home/components/user/{RecommendCardDialog.vue => recommend-card-dialog.vue} (97%) rename apps/web-antd/src/views/im/home/components/user/{UserAvatar.vue => user-avatar.vue} (97%) rename apps/web-antd/src/views/im/home/components/user/{UserInfoCard.vue => user-info-card.vue} (98%) rename apps/web-antd/src/views/im/home/components/user/{UserInfo.vue => user-info.vue} (99%) rename apps/web-antd/src/views/im/home/pages/contact/{FriendList.vue => friend-list.vue} (97%) rename apps/web-antd/src/views/im/home/pages/contact/{FriendRequestDetail.vue => friend-request-detail.vue} (98%) rename apps/web-antd/src/views/im/home/pages/contact/{FriendRequestList.vue => friend-request-list.vue} (98%) rename apps/web-antd/src/views/im/home/pages/contact/{GroupDetail.vue => group-detail.vue} (90%) rename apps/web-antd/src/views/im/home/pages/contact/{GroupList.vue => group-list.vue} (96%) rename apps/web-antd/src/views/im/home/pages/conversation/components/conversation/{ConversationGroupSide.vue => conversation-group-side.vue} (98%) rename apps/web-antd/src/views/im/home/pages/conversation/components/conversation/{ConversationItem.vue => conversation-item.vue} (98%) rename apps/web-antd/src/views/im/home/pages/conversation/components/conversation/{ConversationPrivateSide.vue => conversation-private-side.vue} (98%) create mode 100644 apps/web-antd/src/views/im/home/pages/conversation/components/conversation/index.ts create mode 100644 apps/web-antd/src/views/im/home/pages/conversation/components/index.ts rename apps/web-antd/src/views/im/home/pages/conversation/components/input/{FacePicker.vue => face-picker.vue} (100%) create mode 100644 apps/web-antd/src/views/im/home/pages/conversation/components/input/index.ts rename apps/web-antd/src/views/im/home/pages/conversation/components/input/{MentionPicker.vue => mention-picker.vue} (98%) rename apps/web-antd/src/views/im/home/pages/conversation/components/input/{MessageInput.vue => message-input.vue} (98%) rename apps/web-antd/src/views/im/home/pages/conversation/components/input/{MessageMultiSelectBar.vue => message-multi-select-bar.vue} (100%) rename apps/web-antd/src/views/im/home/pages/conversation/components/input/{VoiceRecorder.vue => voice-recorder.vue} (100%) create mode 100644 apps/web-antd/src/views/im/home/pages/conversation/components/message/forward/index.ts rename apps/web-antd/src/views/im/home/pages/conversation/components/message/forward/{MessageForwardDialog.vue => message-forward-dialog.vue} (98%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/forward/{MessageMergeDetailDialog.vue => message-merge-detail-dialog.vue} (96%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{GroupPinnedMessage.vue => group-pinned-message.vue} (100%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{GroupRequestPending.vue => group-request-pending.vue} (97%) create mode 100644 apps/web-antd/src/views/im/home/pages/conversation/components/message/index.ts rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{MaterialBubble.vue => material-bubble.vue} (100%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{MessageBubble.vue => message-bubble.vue} (97%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{MessageHistory.vue => message-history.vue} (99%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{MessageItem.vue => message-item.vue} (99%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{MessagePanel.vue => message-panel.vue} (97%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{MessageReadStatus.vue => message-read-status.vue} (97%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{ReplyPreview.vue => reply-preview.vue} (99%) rename apps/web-antd/src/views/im/home/pages/conversation/components/message/{TipSegments.vue => tip-segments.vue} (100%) create mode 100644 apps/web-antd/src/views/im/manager/channel/list/components/index.ts rename apps/web-antd/src/views/im/manager/{components/ChannelSelect.vue => channel/list/components/select.vue} (100%) create mode 100644 apps/web-antd/src/views/im/manager/channel/material/components/index.ts rename apps/web-antd/src/views/im/manager/{components/MaterialSelect.vue => channel/material/components/select.vue} (100%) delete mode 100644 apps/web-antd/src/views/im/manager/components/GroupSelect.vue delete mode 100644 apps/web-antd/src/views/im/manager/components/UserMultiSelect.vue create mode 100644 apps/web-antd/src/views/im/manager/group/components/index.ts create mode 100644 apps/web-antd/src/views/im/manager/group/components/select-dialog.vue create mode 100644 apps/web-antd/src/views/im/manager/group/components/select.vue rename apps/web-antd/src/views/im/manager/message/{MessageContentPreview.vue => content-preview.vue} (98%) create mode 100644 apps/web-antd/src/views/im/manager/message/index.ts rename apps/web-antd/src/views/im/manager/statistics/components/{DistributionChart.vue => distribution-chart.vue} (100%) create mode 100644 apps/web-antd/src/views/im/manager/statistics/components/index.ts rename apps/web-antd/src/views/im/manager/statistics/components/{OverviewCards.vue => overview-cards.vue} (100%) rename apps/web-antd/src/views/im/manager/statistics/components/{TrendChart.vue => trend-chart.vue} (100%) diff --git a/apps/web-antd/src/api/system/user/index.ts b/apps/web-antd/src/api/system/user/index.ts index caa0204a9..1f4903682 100644 --- a/apps/web-antd/src/api/system/user/index.ts +++ b/apps/web-antd/src/api/system/user/index.ts @@ -41,6 +41,13 @@ export function getUser(id: number) { return requestClient.get(`/system/user/get?id=${id}`); } +/** 查询用户列表 */ +export function getUserList(ids: number[]) { + return requestClient.get('/system/user/list', { + params: { ids: ids.join(',') }, + }); +} + /** 新增用户 */ export function createUser(data: SystemUserApi.User) { return requestClient.post('/system/user/create', data); diff --git a/apps/web-antd/src/views/im/home/components/card/CardBubble.vue b/apps/web-antd/src/views/im/home/components/card/card-bubble.vue similarity index 97% rename from apps/web-antd/src/views/im/home/components/card/CardBubble.vue rename to apps/web-antd/src/views/im/home/components/card/card-bubble.vue index ce5c0d239..0fb56daa5 100644 --- a/apps/web-antd/src/views/im/home/components/card/CardBubble.vue +++ b/apps/web-antd/src/views/im/home/components/card/card-bubble.vue @@ -8,7 +8,7 @@ import { getCardLabelInfo } from '#/views/im/utils/message' -import UserAvatar from '../user/UserAvatar.vue' +import { UserAvatar } from '../user' defineOptions({ name: 'ImCardBubble' }) diff --git a/apps/web-antd/src/views/im/home/components/card/CardLineLabel.vue b/apps/web-antd/src/views/im/home/components/card/card-line-label.vue similarity index 100% rename from apps/web-antd/src/views/im/home/components/card/CardLineLabel.vue rename to apps/web-antd/src/views/im/home/components/card/card-line-label.vue diff --git a/apps/web-antd/src/views/im/home/components/card/index.ts b/apps/web-antd/src/views/im/home/components/card/index.ts new file mode 100644 index 000000000..ac62b1b09 --- /dev/null +++ b/apps/web-antd/src/views/im/home/components/card/index.ts @@ -0,0 +1,2 @@ +export { default as CardBubble } from './card-bubble.vue'; +export { default as CardLineLabel } from './card-line-label.vue'; diff --git a/apps/web-antd/src/views/im/home/components/ContextMenu.vue b/apps/web-antd/src/views/im/home/components/context-menu.vue similarity index 100% rename from apps/web-antd/src/views/im/home/components/ContextMenu.vue rename to apps/web-antd/src/views/im/home/components/context-menu.vue diff --git a/apps/web-antd/src/views/im/home/components/friend/FriendAddDialog.vue b/apps/web-antd/src/views/im/home/components/friend/friend-add-dialog.vue similarity index 98% rename from apps/web-antd/src/views/im/home/components/friend/FriendAddDialog.vue rename to apps/web-antd/src/views/im/home/components/friend/friend-add-dialog.vue index e83172b6a..bd8578848 100644 --- a/apps/web-antd/src/views/im/home/components/friend/FriendAddDialog.vue +++ b/apps/web-antd/src/views/im/home/components/friend/friend-add-dialog.vue @@ -14,7 +14,7 @@ import { getCurrentUserId } from '#/views/im/utils/auth' import { ImFriendAddSource } from '../../../utils/constants' import { getGenderColor, getGenderIcon } from '../../../utils/user' import { useFriendStore } from '../../store/friendStore' -import UserAvatar from '../user/UserAvatar.vue' +import { UserAvatar } from '../user' defineOptions({ name: 'ImFriendAddDialog' }) @@ -159,7 +159,13 @@ async function handleSubmitApply() { - 第一层 search:按昵称搜索用户列表 - 第二层 apply:选中用户后展开「申请添加朋友」表单(申请理由 + 备注) --> - +