From c80902dab3233701584284cdd2e84f624105f05c Mon Sep 17 00:00:00 2001 From: ysn <2126564605@qq.com> Date: Tue, 16 Jun 2026 10:36:45 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=8F=B3=E4=B8=8A=E8=A7=92=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=202.=E5=8F=91=E8=B5=B7=E7=BE=A4=E8=81=8A?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E4=BF=AE=E6=94=B9=203.=E9=A6=96=E9=A1=B5-?= =?UTF-8?q?=E8=A7=86=E8=AE=AF=E6=A0=B7=E5=BC=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/components/Navbar.vue | 5 +- .../message/components/CreateGroupDialog.vue | 303 +++++++++++++----- src/views/videoCommunication/index.vue | 19 +- 3 files changed, 235 insertions(+), 92 deletions(-) diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index a10c285..b0fcb68 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -117,10 +117,7 @@
- 所属单位: - - {{ userInfo.group }} - + 所属单位:{{ userInfo.group }}
diff --git a/src/views/message/components/CreateGroupDialog.vue b/src/views/message/components/CreateGroupDialog.vue index c8321ea..cb55364 100644 --- a/src/views/message/components/CreateGroupDialog.vue +++ b/src/views/message/components/CreateGroupDialog.vue @@ -21,11 +21,15 @@ style="margin-bottom: 10px" /> - - + + -
+
+
+ 加载更多... +
+
+ 没有更多数据了 +
-
+
+
+ 加载更多... +
+
+ 没有更多数据了 +
@@ -196,6 +222,47 @@
+ + +
+
同事
+
+
+ +
+ + {{ member.name }} + +
+
+
+ +
+
@@ -299,11 +366,18 @@ export default { activeName: "recentContacts", searchText: "", loading: false, + loadMoreLoading: false, confirmLoading: false, selectedMembers: [], + contactPage: 1, + groupPage: 1, + pageSize: 10, memberList: [], recentGroups: [], treeData: [], + contactNoMore: false, // 联系人无更多标识 + groupNoMore: false, // 群组无更多标识 + isSearching: false, }; }, computed: { @@ -320,27 +394,45 @@ export default { methods: { show() { this.visible = true; + this.resetPage(); this.loadData(); }, + // 重置分页、无更多标记、列表数据 + resetPage() { + this.contactPage = 1; + this.groupPage = 1; + this.contactNoMore = false; + this.groupNoMore = false; + this.memberList = []; + this.recentGroups = []; + }, async loadData() { await Promise.all([ - this.fetchRecentContacts(), - this.fetchRecentGroups(), + this.fetchRecentContacts(true), + this.fetchRecentGroups(true), this.fetchOrgTree(), ]); }, - // 获取最近联系人 - async fetchRecentContacts() { - this.loading = true; + /** + * 获取联系人列表 + * @param {Boolean} isReset true=首页刷新,false=滚动追加 + */ + async fetchRecentContacts(isReset = false) { + // 已经无更多且不是刷新首页,直接return + if (this.contactNoMore && !isReset) return; + + if (isReset) this.loading = true; + else this.loadMoreLoading = true; + try { const res = await getMessagesLatestContacts({ scene: 1, - page: 1, - size: 65535, + page: this.contactPage, + size: this.pageSize, }); const list = res.data?.list || []; - this.memberList = list.map((item) => ({ + const formatList = list.map((item) => ({ id: item.id, name: item.name, role: item.role, @@ -353,24 +445,47 @@ export default { online: item.online === 1 || item.online === true, selected: this.isSelected(item.id), })); + + if (isReset) { + this.memberList = formatList; + } else { + this.memberList.push(...formatList); + } + + // 核心判断:返回条数 < 每页条数,标记无更多,后续不再触底加载 + if (list.length < this.pageSize) { + this.contactNoMore = true; + } else { + this.contactNoMore = false; + } } catch (e) { console.error("获取最近联系人失败", e); - this.memberList = []; + if (isReset) this.memberList = []; } finally { this.loading = false; + this.loadMoreLoading = false; } }, - // 获取最近群组 - async fetchRecentGroups() { + // 触底加载更多联系人 + loadMoreContacts() { + // 正在加载 / 无更多 直接阻断 + if (this.loadMoreLoading || this.contactNoMore) return; + this.contactPage++; + this.fetchRecentContacts(false); + }, + + async fetchRecentGroups(isReset = false) { + if (this.groupNoMore && !isReset) return; + try { const res = await getMessagesLatestContacts({ scene: 4, - page: 1, - size: 65535, + page: this.groupPage, + size: this.pageSize, }); const list = res.data?.list || []; - this.recentGroups = list.map((item) => ({ + const formatGroups = list.map((item) => ({ id: item.id, name: item.name, avatar: item.avatar, @@ -378,13 +493,32 @@ export default { allSelected: false, members: [], })); + + if (isReset) { + this.recentGroups = formatGroups; + } else { + this.recentGroups.push(...formatGroups); + } + + // 核心判断:返回条数不足一页,关闭触底加载 + if (list.length < this.pageSize) { + this.groupNoMore = true; + } else { + this.groupNoMore = false; + } } catch (e) { console.error("获取最近群组失败", e); - this.recentGroups = []; + if (isReset) this.recentGroups = []; } }, - // 获取组织架构树 + // 触底加载更多群组 + loadMoreGroups() { + if (this.loadMoreLoading || this.groupNoMore) return; + this.groupPage++; + this.fetchRecentGroups(false); + }, + async fetchOrgTree() { try { const res = await getGroupsList(); @@ -396,7 +530,22 @@ export default { } }, - // 构建组织架构树 + // 滚动触底统一处理 + handleScroll(e) { + const target = e.target; + const scrollTop = target.scrollTop; + const scrollHeight = target.scrollHeight; + const clientHeight = target.clientHeight; + // 距离底部50px触发加载 + if (scrollTop + clientHeight >= scrollHeight - 50) { + if (this.activeName === "recentContacts") { + this.loadMoreContacts(); + } else if (this.activeName === "recentGroups") { + this.loadMoreGroups(); + } + } + }, + buildOrgTree(list) { if (!list || list.length === 0) return []; return list.map((item) => ({ @@ -412,7 +561,6 @@ export default { })); }, - // 加载组织下的用户 async loadOrgUsers(node) { if (node.isLoaded || node.type === "user" || node.type === "all") return; if (node.hasChildren && node.children && node.children.length > 0) { @@ -450,13 +598,15 @@ export default { } }, - // 搜索联系人 async handleSearch() { const text = this.searchText.trim(); if (!text) { - await this.fetchRecentContacts(); + this.isSearching = false; + this.resetPage(); + await this.fetchRecentContacts(true); return; } + this.isSearching = true; this.loading = true; try { const res = await searchUsers({ @@ -479,6 +629,8 @@ export default { online: item.online === 1 || item.online === true, selected: this.isSelected(item.id), })); + // 搜索结果一次性返回,关闭分页加载 + this.contactNoMore = true; } catch (e) { console.error("搜索联系人失败", e); } finally { @@ -486,21 +638,16 @@ export default { } }, - // 清除搜索 handleClearSearch() { this.searchText = ""; - this.fetchRecentContacts(); + this.resetPage(); + this.fetchRecentContacts(true); }, - // 点击标签页 handleClick(tab) { this.activeName = tab.name; - if (tab.name === "recentGroups") { - this.loadGroupMembers(); - } }, - // 加载群组成员 async loadGroupMembers() { for (const group of this.recentGroups) { if (!group.members || group.members.length === 0) { @@ -522,17 +669,13 @@ export default { } }, - // 切换群组展开 async toggleGroupExpand(group) { group.expanded = !group.expanded; if (group.expanded) { - // 调用 getMultiChatInfo 接口获取群详细信息 try { const res = await getMultiChatInfo({ multi_chat_id: group.id }); const data = res.data || {}; - // 使用接口返回的成员列表,过滤掉与 user_id 相同的用户 const userList = data.user_list || []; - // 获取当前用户ID,用于过滤掉自己 group.members = userList .filter((item) => item.id !== data.user_id) .map((item) => { @@ -545,23 +688,19 @@ export default { } }, - // 点击组织节点 async handleOrgNodeClick(data) { if (data.type === "org") { this.$refs.orgTree.setCurrentKey(data.id); - // 加载用户数据(只在首次展开时加载) if (!data.isLoaded) { await this.loadOrgUsers(data); } } }, - // 判断是否已选中 isSelected(userId) { return this.selectedMembers.some((m) => m.id === userId); }, - // 切换选择状态 toggleSelect(member) { if (this.isSelectDisabled && !member.selected) { this.$message.warning(`最多只能选择${this.maxSelectCount}个成员`); @@ -582,13 +721,10 @@ export default { this.syncSelection(member); }, - // 同步选择状态 syncSelection(member) { - // 同步最近联系人 this.memberList.forEach((m) => { if (m.id === member.id) m.selected = member.selected; }); - // 同步最近群组 this.recentGroups.forEach((group) => { if (group.members) { const groupMember = group.members.find((m) => m.id === member.id); @@ -598,11 +734,9 @@ export default { } } }); - // 同步组织架构 this.syncOrgTreeSelection(this.treeData, member); }, - // 同步组织架构选择状态 syncOrgTreeSelection(nodes, member) { nodes.forEach((node) => { if (node.id === member.id && node.type === "user") { @@ -615,7 +749,6 @@ export default { }); }, - // 切换群组全选 toggleGroupAllSelect(group) { if (!group.members || group.members.length === 0) return; if (group.allSelected) { @@ -624,16 +757,14 @@ export default { const index = this.selectedMembers.findIndex( (m) => m.id === member.id ); - if (index >= 0) { - this.selectedMembers.splice(index, 1); - } + if (index >= 0) this.selectedMembers.splice(index, 1); }); group.allSelected = false; } else { - const selectedCount = group.members.filter((m) => !m.selected).length; + const unselectedCount = group.members.filter((m) => !m.selected).length; if ( this.maxSelectCount > 0 && - this.selectedMembers.length + selectedCount > this.maxSelectCount + this.selectedMembers.length + unselectedCount > this.maxSelectCount ) { this.$message.warning(`最多只能选择${this.maxSelectCount}个成员`); return; @@ -653,14 +784,10 @@ export default { this.syncGroupSelection(group); }, - // 同步群组选择到其他列表 syncGroupSelection(group) { - group.members.forEach((member) => { - this.syncSelection(member); - }); + group.members.forEach((member) => this.syncSelection(member)); }, - // 组织架构全选 handleOrgCheckAllChange(allNode) { const parentNode = this.findParentNode(this.treeData, allNode.id); if (!parentNode || !parentNode.children) return; @@ -693,16 +820,13 @@ export default { users.forEach((user) => { user.selected = false; const index = this.selectedMembers.findIndex((m) => m.id === user.id); - if (index >= 0) { - this.selectedMembers.splice(index, 1); - } + if (index >= 0) this.selectedMembers.splice(index, 1); }); allNode.indeterminate = false; } users.forEach((user) => this.syncSelection(user)); }, - // 查找父节点 findParentNode(nodes, childId, parent = null) { for (const node of nodes) { if (node.id === childId) return parent; @@ -714,7 +838,6 @@ export default { return null; }, - // 更新父节点全选状态 updateParentAllSelectStatus(userNode) { const parentNode = this.findParentNode(this.treeData, userNode.id); if (!parentNode || !parentNode.children) return; @@ -728,17 +851,14 @@ export default { } }, - // 移除已选人员 removeSelected(member) { const index = this.selectedMembers.findIndex((m) => m.id === member.id); if (index >= 0) { this.selectedMembers.splice(index, 1); - member.selected = false; this.syncSelection({ id: member.id, selected: false }); } }, - // 清空所有选择 clearAllSelected() { this.selectedMembers = []; this.memberList.forEach((m) => (m.selected = false)); @@ -749,7 +869,6 @@ export default { this.clearOrgTreeSelected(this.treeData); }, - // 清空组织架构选择 clearOrgTreeSelected(nodes) { nodes.forEach((node) => { node.selected = false; @@ -757,14 +876,13 @@ export default { }); }, - // 关闭弹窗 handleClose(done) { this.clearAllSelected(); this.searchText = ""; + this.resetPage(); this.visible = false; }, - // 确认创建群聊 async confirmCreateGroup() { if (this.selectedMembers.length < this.minSelectCount) { this.$message.warning(`至少选择${this.minSelectCount}个成员`); @@ -772,13 +890,10 @@ export default { } this.confirmLoading = true; try { - // 1. 先执行 props 传入的回调 if (typeof this.confirmCallback === "function") { await this.confirmCallback(this.selectedMembers); } - // 2. 触发 confirm 事件 this.$emit("confirm", this.selectedMembers); - // 3. 清空选择并关闭弹窗 this.clearAllSelected(); this.searchText = ""; this.visible = false; @@ -796,10 +911,28 @@ export default { .body { height: 450px; + .search-result-wrap { + .search-title { + font-size: 14px; + font-weight: 500; + color: #606266; + padding: 6px 0 8px; + border-bottom: 1px solid #ebeef5; + margin-bottom: 8px; + } + } + .contact-list { height: 400px; overflow-y: auto; + .load-more-tip { + text-align: center; + padding: 8px 0; + color: #909399; + font-size: 13px; + } + .member-item { display: flex; align-items: center; @@ -809,6 +942,15 @@ export default { border-radius: 4px; transition: background 0.2s; + // 修复el-checkbox内部垂直偏移 + ::v-deep .el-checkbox { + display: flex; + align-items: center; + } + ::v-deep .el-checkbox__inner { + margin-top: 0 !important; + } + &:hover { background: #f5f7fa; } @@ -887,6 +1029,21 @@ export default { padding: 5px; } + // 组织树用户行修复复选框下沉 + .userline { + display: flex; + align-items: center; + gap: 10px; + padding: 8px 16px; + ::v-deep .el-checkbox { + display: flex; + align-items: center; + } + ::v-deep .el-checkbox__inner { + margin-top: 0 !important; + } + } + .org-icon { font-size: 16px; color: #409eff; @@ -983,14 +1140,6 @@ export default { justify-content: center; } - .userline { - display: flex; - align-items: center; - gap: 10px; - padding: 8px 16px; - } - - // 群组详细信息样式 .group-detail-info { padding: 12px 16px; margin: 8px 0; diff --git a/src/views/videoCommunication/index.vue b/src/views/videoCommunication/index.vue index f525c28..3b97270 100644 --- a/src/views/videoCommunication/index.vue +++ b/src/views/videoCommunication/index.vue @@ -59,28 +59,22 @@ /> - + @@ -342,6 +336,9 @@ export default { margin-right: 8px; } } + .table-column { + color: #009696; + } // 口令入会区域 .join-area {