ConversationList State

最近更新时间:2025-09-12 18:14:52

我的收藏

概述

ConversationListState 是基于 Vue 3 Composition API 的会话列表状态管理钩子,为 ConversationList 组件提供完整的状态管理能力。它管理会话列表数据、当前活跃会话、未读消息数量、网络状态等,并提供会话操作的相关方法。

数据

属性名
类型
说明
conversationList
Ref<ConversationModel[] | undefined>
会话列表数据
activeConversation
Ref<ConversationModel | undefined>
当前活跃的会话
totalUnRead
Ref<number>
未读消息总数
netStatus
Ref<NET_STATE_CONNECTED | NET_STATE_CONNECTING | NET_STATE_DISCONNECTED>
网络连接状态

方法

方法名
类型
说明
setActiveConversation
(conversationID: string) => void
设置当前活跃会话
createC2CConversation
(userID: string) => Promise<ConversationModel>
创建私聊会话
createGroupConversation
(options: CreateGroupParams) => Promise<ConversationModel>
创建群聊会话
pinConversation
(conversationID: string, isPin: boolean) => Promise<unknown>
置顶/取消置顶会话
deleteConversation
(conversationID: string) => Promise<unknown>
删除会话
muteConversation
(conversationID: string, isMute: boolean) => Promise<unknown>
免打扰/取消免打扰
setConversationDraft
(options: SetConversationDraftParams) => Promise<unknown>
设置会话草稿
markConversationUnread
(conversationID: string, isUnread: boolean) => void
标记会话已读/未读

网络状态

支持以下网络状态类型:
NET_STATE_CONNECTED:已连接
NET_STATE_CONNECTING:连接中
NET_STATE_DISCONNECTED:已断开

使用示例

基础会话列表

<template>
<div class="conversation-list">
<div class="header">
<h3>会话列表</h3>
<div v-if="totalUnRead > 0" class="unread-badge">
{{ totalUnRead }}
</div>
</div>

<div class="list">
<div
v-for="conversation in conversationList"
:key="conversation.conversationID"
:class="[
'conversation-item',
{ active: activeConversation?.conversationID === conversation.conversationID }
]"
@click="setActiveConversation(conversation.conversationID)"
>
<div class="avatar">
<img :src="conversation.getAvatar()" alt="头像" />
</div>
<div class="content">
<div class="name">{{ conversation.getShowName() }}</div>
<div class="last-message">{{ conversation.lastMessage?.messageForShow }}</div>
</div>
<div v-if="conversation.unreadCount > 0" class="unread-count">
{{ conversation.unreadCount }}
</div>
</div>
</div>
</div>
</template>

<script setup lang="ts">
import { useConversationListState } from '@tencentcloud/chat-uikit-vue3';

const {
conversationList,
activeConversation,
totalUnRead,
setActiveConversation
} = useConversationListState();
</script>

<style scoped>
.conversation-list {
width: 300px;
height: 100%;
border-right: 1px solid #e0e0e0;
}

.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #f0f0f0;
}

.unread-badge {
background: #ff4d4f;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 600;
}

.conversation-item {
display: flex;
align-items: center;
padding: 12px 16px;
cursor: pointer;
border-bottom: 1px solid #f5f5f5;
transition: background-color 0.2s;
}

.conversation-item:hover {
background-color: #f5f5f5;
}

.conversation-item.active {
background-color: #e6f7ff;
border-left: 3px solid #1890ff;
}

.avatar {
width: 40px;
height: 40px;
margin-right: 12px;
}

.avatar img {
width: 100%;
height: 100%;
border-radius: 50%;
object-fit: cover;
}

.content {
flex: 1;
min-width: 0;
}

.name {
font-weight: 500;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.last-message {
font-size: 13px;
color: #999;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.unread-count {
background: #52c41a;
color: white;
border-radius: 10px;
padding: 2px 6px;
font-size: 12px;
font-weight: 600;
min-width: 18px;
text-align: center;
}
</style>
效果如图:


会话操作功能

<template>
<div class="conversation-with-actions">
<div
v-for="conversation in conversationList"
:key="conversation.conversationID"
class="conversation-item"
>
<div class="conversation-info">
<div class="name">{{ conversation.getShowName() }}</div>
<div class="status">
<span v-if="conversation.isPinned" class="pin-badge">📌 置顶</span>
<span v-if="conversation.isMuted" class="mute-badge">🔕 免打扰</span>
<span v-if="conversation.unreadCount > 0" class="unread-badge">
{{ conversation.unreadCount }}
</span>
</div>
</div>

<div class="conversation-actions">
<button
@click="handlePin(conversation.conversationID, !conversation.isPinned)"
:class="{ active: conversation.isPinned }"
>
{{ conversation.isPinned ? '取消置顶' : '置顶' }}
</button>

<button
@click="handleMute(conversation.conversationID, !conversation.isMuted)"
:class="{ active: conversation.isMuted }"
>
{{ conversation.isMuted ? '取消免打扰' : '免打扰' }}
</button>

<button
@click="handleMarkUnread(conversation.conversationID, conversation.unreadCount === 0)"
>
{{ conversation.unreadCount > 0 ? '标记已读' : '标记未读' }}
</button>

<button
@click="handleDelete(conversation.conversationID)"
class="danger"
>
删除
</button>
</div>
</div>
</div>
</template>

<script setup lang="ts">
import { useConversationListState } from '@tencentcloud/chat-uikit-vue3';

const {
conversationList,
pinConversation,
deleteConversation,
muteConversation,
markConversationUnread
} = useConversationListState();

const handlePin = async (conversationID: string, isPin: boolean) => {
try {
await pinConversation(conversationID, isPin);
console.log(`会话${isPin ? '置顶' : '取消置顶'}成功`);
} catch (error) {
console.error('置顶操作失败:', error);
}
};

const handleDelete = async (conversationID: string) => {
if (confirm('确定要删除这个会话吗?')) {
try {
await deleteConversation(conversationID);
console.log('会话删除成功');
} catch (error) {
console.error('删除会话失败:', error);
}
}
};

const handleMute = async (conversationID: string, isMute: boolean) => {
try {
await muteConversation(conversationID, isMute);
console.log(`会话${isMute ? '设置' : '取消'}免打扰成功`);
} catch (error) {
console.error('免打扰设置失败:', error);
}
};

const handleMarkUnread = (conversationID: string, isUnread: boolean) => {
markConversationUnread(conversationID, isUnread);
console.log(`会话标记为${isUnread ? '未读' : '已读'}`);
};
</script>

<style scoped>
.conversation-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #f0f0f0;
}

.conversation-info {
flex: 1;
}

.name {
font-weight: 500;
margin-bottom: 8px;
}

.status {
display: flex;
gap: 8px;
align-items: center;
}

.pin-badge, .mute-badge {
font-size: 12px;
color: #666;
}

.unread-badge {
background: #52c41a;
color: white;
border-radius: 10px;
padding: 2px 6px;
font-size: 12px;
font-weight: 600;
}

.conversation-actions {
display: flex;
gap: 8px;
}

.conversation-actions button {
padding: 6px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
background: white;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
}

.conversation-actions button:hover {
border-color: #1890ff;
color: #1890ff;
}

.conversation-actions button.active {
background: #1890ff;
border-color: #1890ff;
color: white;
}

.conversation-actions button.danger {
border-color: #ff4d4f;
color: #ff4d4f;
}

.conversation-actions button.danger:hover {
background: #ff4d4f;
color: white;
}
</style>
效果如图:


创建会话功能

<template>
<div class="conversation-creator">
<div class="create-c2c">
<h4>创建私聊</h4>
<div class="form-group">
<input
v-model="userID"
type="text"
placeholder="输入用户ID"
@keyup.enter="handleCreateC2C"
/>
<button @click="handleCreateC2C" :disabled="!userID.trim()">
创建私聊
</button>
</div>
</div>

<div class="create-group">
<h4>创建群聊</h4>
<div class="form-group">
<input
v-model="groupName"
type="text"
placeholder="输入群组名称"
/>
</div>

<div class="form-group">
<label>群组类型:</label>
<select v-model="groupType">
<option value="Work">工作群</option>
<option value="Public">公开群</option>
<option value="Meeting">会议群</option>
</select>
</div>

<div class="member-selector">
<label>群成员 (用户ID,逗号分隔):</label>
<textarea
v-model="memberList"
placeholder="user1,user2,user3"
rows="3"
></textarea>
</div>

<button
@click="handleCreateGroup"
:disabled="!groupName.trim() || !memberList.trim()"
>
创建群聊
</button>
</div>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { useConversationListState } from '@tencentcloud/chat-uikit-vue3';
import type { CreateGroupParams } from '@tencentcloud/chat-uikit-engine';

const {
createC2CConversation,
createGroupConversation,
setActiveConversation
} = useConversationListState();

const userID = ref('');
const groupName = ref('');
const groupType = ref<'Work' | 'Public' | 'Meeting'>('Work');
const memberList = ref('');

const handleCreateC2C = async () => {
if (!userID.value.trim()) {
alert('请输入用户ID');
return;
}

try {
const conversation = await createC2CConversation(userID.value);
setActiveConversation(conversation.conversationID);
console.log('私聊创建成功:', conversation.conversationID);
userID.value = '';
} catch (error) {
console.error('创建私聊失败:', error);
alert('创建私聊失败,请检查用户ID是否正确');
}
};

const handleCreateGroup = async () => {
if (!groupName.value.trim()) {
alert('请输入群组名称');
return;
}

if (!memberList.value.trim()) {
alert('请输入群成员');
return;
}

try {
const members = memberList.value.split(',')
.map(id => id.trim())
.filter(id => id)
.map(userID => ({ userID }));

if (members.length === 0) {
alert('请输入有效的群成员ID');
return;
}

const groupParams: CreateGroupParams = {
name: groupName.value,
memberList: members,
type: groupType.value,
};

const conversation = await createGroupConversation(groupParams);
setActiveConversation(conversation.conversationID);
console.log('群聊创建成功:', conversation.conversationID);

// 重置表单
groupName.value = '';
memberList.value = '';
groupType.value = 'Work';
} catch (error) {
console.error('创建群聊失败:', error);
alert('创建群聊失败,请检查参数是否正确');
}
};
</script>

<style scoped>
.conversation-creator {
padding: 20px;
max-width: 500px;
}

.create-c2c, .create-group {
background: #f9f9f9;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
}

.create-c2c h4, .create-group h4 {
margin: 0 0 16px 0;
color: #333;
}

.form-group {
display: flex;
gap: 12px;
margin-bottom: 16px;
align-items: center;
}

.form-group:last-child {
margin-bottom: 0;
}

.form-group label {
min-width: 80px;
font-weight: 500;
}

.form-group input,
.form-group select,
.form-group textarea {
flex: 1;
padding: 8px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
}

.form-group textarea {
resize: vertical;
font-family: inherit;
}

.member-selector {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 16px;
}

.member-selector label {
font-weight: 500;
color: #333;
}

button {
padding: 8px 16px;
background: #1890ff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
}

button:hover:not(:disabled) {
background: #40a9ff;
}

button:disabled {
background: #d9d9d9;
cursor: not-allowed;
}
</style>
效果如图: