ContactList Store

最近更新时间:2026-07-01 16:34:31

我的收藏

概述

ContactListStore 提供完整的联系人相关的数据管理能力。它支持好友列表、群组列表、黑名单和申请管理等功能。如果自定义组件能力不能支持您的业务,可以使用 ContactListStore 实现您的需求。

属性

数据名
类型
说明
friendList
ContactInfo[]
好友列表。每项包含用户 ID、昵称、头像、好友备注、在线状态、是否好友、是否在黑名单等信息。
friendApplicationList
FriendApplicationInfo[]
好友申请列表。包含收到/发出的好友申请信息。
friendApplicationUnreadCount
number
好友申请未读数量。
blackList
ContactInfo[]
黑名单列表。每项同样使用 ContactInfo 数据结构,并标记 isInBlacklist: true。

方法

方法名
类型
说明
loadFriends
() => Promise<void>
加载好友列表,并补充好友关系、黑名单状态和在线状态。
addFriend
(params: AddFriendParams) => Promise<void>
添加好友。参数包含 userID、source、remark、addWording。
deleteFriend
(userID: string) => Promise<void>
删除指定好友,并本地更新 friendList。
setFriendRemark
(userID: string, remark: string) => Promise<void>
设置好友备注,并本地更新该好友的 friendRemark。
getContactInfo
(userIDList: string[]) => Promise<ContactInfo[]>
批量获取用户资料,并结合当前好友列表、黑名单状态返回标准 ContactInfo。
loadBlackList
() => Promise<void>
加载黑名单列表,并同步更新好友列表中的 isInBlacklist 状态。
addToBlacklist
(userID: string) => Promise<void>
将指定用户加入黑名单,并本地更新 blackList 与 friendList。
removeFromBlacklist
(userID: string) => Promise<void>
将指定用户移出黑名单,并本地更新 blackList 与 friendList。
loadFriendApplications
() => Promise<void>
加载好友申请列表和未读申请数量。
acceptFriendApplication
(info: FriendApplicationInfo) => Promise<void>
同意好友申请。状态更新依赖 SDK 事件同步。
refuseFriendApplication
(info: FriendApplicationInfo) => Promise<void>
拒绝好友申请。状态更新依赖 SDK 事件同步。
clearFriendApplicationUnreadCount
() => Promise<void>
标记好友申请为已读,并将本地未读数置为 0。
destroy
() => void
注销事件监听、清理在线状态订阅和 Store 状态。通常由框架封装层管理。

使用示例

<script setup lang="ts">
import { onMounted } from 'vue';
import {
ContactStore,
GroupStore,
} from '@tencentcloud/chat-uikit-vue3';

const {
friendList,
loadFriends,
} = ContactStore();

const {
joinedGroupList,
loadJoinedGroups,
} = GroupStore();

onMounted(() => {
loadFriends();
loadJoinedGroups();
});

function getAvatarText(value: string) {
return value.slice(0, 1).toUpperCase();
}
</script>

<template>
<div class="contact-store-basic-demo">
<div class="contact-store-basic-demo__header">
<h2>Contact Store Basic</h2>
<p>Very simple friend and group list powered by ContactStore and GroupStore.</p>
</div>

<div class="contact-store-basic-demo__columns">
<section class="contact-store-basic-demo__panel">
<h3>Friends ({{ friendList.length }})</h3>
<ul v-if="friendList.length > 0" class="contact-store-basic-demo__list">
<li
v-for="friend in friendList"
:key="friend.userID"
class="contact-store-basic-demo__item"
>
<span class="contact-store-basic-demo__avatar">
{{ getAvatarText(friend.friendRemark || friend.nickname || friend.userID) }}
</span>
<span>
<strong>{{ friend.friendRemark || friend.nickname || friend.userID }}</strong>
<small>{{ friend.userID }}</small>
</span>
</li>
</ul>
<div v-else class="contact-store-basic-demo__empty">
No friends.
</div>
</section>

<section class="contact-store-basic-demo__panel">
<h3>Groups ({{ joinedGroupList.length }})</h3>
<ul v-if="joinedGroupList.length > 0" class="contact-store-basic-demo__list">
<li
v-for="group in joinedGroupList"
:key="group.groupID"
class="contact-store-basic-demo__item"
>
<span class="contact-store-basic-demo__avatar">
{{ getAvatarText(group.groupName || group.groupID) }}
</span>
<span>
<strong>{{ group.groupName || group.groupID }}</strong>
<small>{{ group.groupID }}</small>
</span>
</li>
</ul>
<div v-else class="contact-store-basic-demo__empty">
No groups.
</div>
</section>
</div>
</div>
</template>

<style scoped>
.contact-store-basic-demo {
display: flex;
height: 100%;
flex-direction: column;
gap: 20px;
padding: 24px;
overflow: hidden;
}

.contact-store-basic-demo__header h2 {
margin: 0 0 8px;
color: #111827;
font-size: 22px;
}

.contact-store-basic-demo__header p {
margin: 0;
color: #6b7280;
font-size: 14px;
}

.contact-store-basic-demo__columns {
display: grid;
min-height: 0;
flex: 1;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}

.contact-store-basic-demo__panel {
display: flex;
min-width: 0;
min-height: 0;
flex-direction: column;
overflow: hidden;
border: 1px solid #edf0f5;
border-radius: 12px;
background: #fff;
}

.contact-store-basic-demo__panel h3 {
margin: 0;
padding: 14px 16px;
border-bottom: 1px solid #edf0f5;
color: #111827;
font-size: 15px;
}

.contact-store-basic-demo__list {
display: flex;
flex-direction: column;
gap: 8px;
margin: 0;
padding: 12px;
overflow: auto;
list-style: none;
}

.contact-store-basic-demo__item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
border-radius: 10px;
background: #f9fafb;
}

.contact-store-basic-demo__avatar {
display: inline-flex;
width: 32px;
height: 32px;
align-items: center;
justify-content: center;
border-radius: 50%;
background: #eef2ff;
color: #4f46e5;
font-size: 13px;
font-weight: 700;
}

.contact-store-basic-demo__item strong,
.contact-store-basic-demo__item small {
display: block;
}

.contact-store-basic-demo__item strong {
color: #111827;
font-size: 14px;
}

.contact-store-basic-demo__item small {
margin-top: 2px;
color: #6b7280;
font-size: 12px;
}

.contact-store-basic-demo__empty {
padding: 24px;
color: #6b7280;
text-align: center;
}
</style>