+
+
+
+
@@ -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 @@
/>
-
+
-
+
{{ scope.row.name }}
-
+
-
+
{{ scope.row.meet_type_name }}
-
+
@@ -342,6 +336,9 @@ export default {
margin-right: 8px;
}
}
+ .table-column {
+ color: #009696;
+ }
// 口令入会区域
.join-area {