ykt-wxapp/pages/message/message.vue
2026-01-27 17:09:31 +08:00

536 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="message-page">
<!-- 消息列表 -->
<scroll-view
class="message-list"
scroll-y="true"
refresher-enabled
:refresher-triggered="refreshing"
@refresherrefresh="handleRefresh"
@scrolltolower="handleLoadMore"
>
<!-- 加载状态 -->
<view
v-if="loading && conversationList.length === 0"
class="loading-container"
>
<text class="loading-text">加载中...</text>
</view>
<!-- 消息列表项 -->
<view
v-for="conversation in conversationList"
:key="conversation.conversationID"
class="message-item"
@click="handleClickConversation(conversation)"
>
<view class="avatar-container">
<image
class="avatar"
:src="conversation.avatar || '/static/default-avatar.png'"
mode="aspectFill"
/>
<view v-if="conversation.unreadCount > 0" class="unread-badge">
<text class="unread-text">{{
conversation.unreadCount > 99 ? "99+" : conversation.unreadCount
}}</text>
</view>
</view>
<view class="content">
<view class="header">
<text class="name">{{ conversation.name || "未知群聊" }}</text>
<text class="time">{{
formatMessageTime(conversation.lastMessageTime)
}}</text>
</view>
<view class="message-preview">
<text class="preview-text">{{
conversation.lastMessage || "暂无消息"
}}</text>
</view>
</view>
</view>
<!-- 空状态 -->
<view
v-if="!loading && conversationList.length === 0"
class="empty-container"
>
<image class="empty-image" src="/static/empty.svg" mode="aspectFit" />
<text class="empty-text">暂无消息</text>
</view>
<!-- 加载更多 -->
<view v-if="hasMore && conversationList.length > 0" class="load-more">
<text class="load-more-text">{{
loadingMore ? "加载中..." : "上拉加载更多"
}}</text>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref } from "vue";
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
import { storeToRefs } from "pinia";
import useAccountStore from "@/store/account.js";
import { globalTimChatManager } from "@/utils/tim-chat.js";
// 获取登录状态
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
const { initIMAfterLogin } = useAccountStore();
// 状态
const conversationList = ref([]);
const loading = ref(false);
const loadingMore = ref(false);
const hasMore = ref(false);
const refreshing = ref(false);
// 初始化IM
const initIM = async () => {
if (!isIMInitialized.value) {
uni.showLoading({
title: "连接中...",
});
const success = await initIMAfterLogin(openid.value);
uni.hideLoading();
if (!success) {
uni.showToast({
title: "IM连接失败请重试",
icon: "none",
});
return false;
}
} else if (globalTimChatManager && !globalTimChatManager.isLoggedIn) {
uni.showLoading({
title: "重连中...",
});
const reconnected = await globalTimChatManager.ensureIMConnection();
uni.hideLoading();
if (!reconnected) {
return false;
}
}
return true;
};
// 加载会话列表
const loadConversationList = async () => {
if (loading.value) return;
// loading.value = true;
try {
console.log("开始加载群聊列表");
if (!globalTimChatManager || !globalTimChatManager.getGroupList) {
throw new Error("IM管理器未初始化");
}
// 直接调用getGroupList它会自动等待SDK就绪
const result = await globalTimChatManager.getGroupList();
if (result && result.success && result.groupList) {
conversationList.value = result.groupList
.map((group) => ({
conversationID: group.conversationID || `GROUP${group.groupID}`,
groupID: group.groupID,
name: group.patientName
? `${group.patientName}的问诊`
: group.name || "问诊群聊",
avatar: group.avatar || "/static/default-avatar.png",
lastMessage: group.lastMessage || "暂无消息",
lastMessageTime: group.lastMessageTime || Date.now(),
unreadCount: group.unreadCount || 0,
doctorId: group.doctorId,
patientName: group.patientName,
}))
.sort((a, b) => b.lastMessageTime - a.lastMessageTime);
console.log(
"群聊列表加载成功,共",
conversationList.value.length,
"个会话"
);
} else {
console.error("加载群聊列表失败:", result);
uni.showToast({
title: "加载失败,请重试",
icon: "none",
});
}
} catch (error) {
console.error("加载会话列表失败:", error);
uni.showToast({
title: error.message || "加载失败,请重试",
icon: "none",
});
} finally {
loading.value = false;
}
};
// 提取消息预览文本
const extractMessagePreview = (message) => {
if (!message) return "暂无消息";
const payload = message.payload;
if (!payload) return "暂无消息";
// 文本消息
if (message.type === "TIMTextElem") {
return payload.text || "暂无消息";
}
// 图片消息
if (message.type === "TIMImageElem") {
return "[图片]";
}
// 语音消息
if (message.type === "TIMSoundElem") {
return "[语音]";
}
// 视频消息
if (message.type === "TIMVideoFileElem") {
return "[视频]";
}
// 文件消息
if (message.type === "TIMFileElem") {
return "[文件]";
}
// 自定义消息
if (message.type === "TIMCustomElem") {
const description = payload.description;
if (description === "SYSTEM_NOTIFICATION") {
return "[系统消息]";
}
return "[消息]";
}
return "暂无消息";
};
// 设置会话列表监听,实时更新列表
const setupConversationListener = () => {
if (!globalTimChatManager) return;
// 监听会话列表更新事件
globalTimChatManager.setCallback("onConversationListUpdated", (eventData) => {
console.log("会话列表更新事件:", eventData);
// 如果是新消息导致的会话更新
if (eventData.reason === "NEW_MESSAGE_RECEIVED_IN_CURRENT_CONVERSATION" ||
eventData.reason === "NEW_MESSAGE_RECEIVED") {
const conversation = eventData.conversation;
if (!conversation) return;
const conversationID = conversation.conversationID;
const conversationIndex = conversationList.value.findIndex(
(conv) => conv.conversationID === conversationID
);
if (conversationIndex !== -1) {
// 更新现有会话
const existingConversation = conversationList.value[conversationIndex];
existingConversation.lastMessage = conversation.lastMessage || "暂无消息";
existingConversation.lastMessageTime = conversation.lastMessageTime || Date.now();
existingConversation.unreadCount = conversation.unreadCount || 0;
// 将该会话移到顶部
const [updatedConversation] = conversationList.value.splice(
conversationIndex,
1
);
conversationList.value.unshift(updatedConversation);
console.log("已更新会话:", existingConversation.name);
} else {
// 新会话,添加到列表顶部
conversationList.value.unshift({
conversationID: conversationID,
groupID: conversation.groupID || conversationID.replace("GROUP", ""),
name: conversation.name || "问诊群聊",
avatar: conversation.avatar || "/static/default-avatar.png",
lastMessage: conversation.lastMessage || "暂无消息",
lastMessageTime: conversation.lastMessageTime || Date.now(),
unreadCount: conversation.unreadCount || 0,
});
console.log("已添加新会话");
}
}
});
// 监听消息接收事件(用于更新未读数)
globalTimChatManager.setCallback("onMessageReceived", (message) => {
console.log("消息列表页面收到新消息:", message);
// 找到对应的会话并更新未读数
const conversationID = message.conversationID;
const conversationIndex = conversationList.value.findIndex(
(conv) => conv.conversationID === conversationID
);
if (conversationIndex !== -1) {
const conversation = conversationList.value[conversationIndex];
// 只更新未读数,其他信息由 onConversationListUpdated 事件处理
conversation.unreadCount = (conversation.unreadCount || 0) + 1;
console.log("已更新会话未读数:", conversation.name);
}
});
};
// 格式化消息时间
const formatMessageTime = (timestamp) => {
if (!timestamp) return "";
const now = Date.now();
const diff = now - timestamp;
const date = new Date(timestamp);
// 1分钟内
if (diff < 60 * 1000) {
return "刚刚";
}
// 1小时内
if (diff < 60 * 60 * 1000) {
return `${Math.floor(diff / (60 * 1000))}分钟前`;
}
// 今天
const today = new Date();
if (date.toDateString() === today.toDateString()) {
return `${String(date.getHours()).padStart(2, "0")}:${String(
date.getMinutes()
).padStart(2, "0")}`;
}
// 昨天
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
if (date.toDateString() === yesterday.toDateString()) {
return "昨天";
}
// 今年
if (date.getFullYear() === today.getFullYear()) {
return `${date.getMonth() + 1}${date.getDate()}`;
}
// 其他
return `${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}`;
};
// 点击会话
const handleClickConversation = (conversation) => {
console.log("点击会话:", conversation);
// 跳转到聊天页面
uni.navigateTo({
url: `/pages/message/index?conversationID=${conversation.conversationID}&groupID=${conversation.groupID}`,
});
};
// 加载更多
const handleLoadMore = () => {
if (loadingMore.value || !hasMore.value) return;
loadingMore.value = true;
// TODO: 实现分页加载
setTimeout(() => {
loadingMore.value = false;
}, 1000);
};
// 下拉刷新
const handleRefresh = async () => {
refreshing.value = true;
try {
await loadConversationList();
} finally {
refreshing.value = false;
}
};
// 页面加载
onLoad(() => {
console.log("消息列表页面加载");
});
// 页面显示
// onShow(async () => {
// try {
// // 初始化IM
// const imReady = await initIM();
// if (!imReady) {
// console.error("IM初始化失败");
// return;
// }
// // 先加载初始会话列表
// await loadConversationList();
// // 再设置监听器,后续通过事件更新列表
// setupConversationListener();
// } catch (error) {
// console.error("页面初始化失败:", error);
// uni.showToast({
// title: "初始化失败,请重试",
// icon: "none",
// });
// }
// });
// 页面隐藏
onHide(() => {
// 移除消息监听
// if (globalTimChatManager) {
// globalTimChatManager.setCallback("onConversationListUpdated", null);
// globalTimChatManager.setCallback("onMessageReceived", null);
// }
});
</script>
<style scoped lang="scss">
.message-page {
width: 100%;
height: 100vh;
background-color: #f5f5f5;
}
.message-list {
width: 100%;
height: 100%;
}
.loading-container,
.empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
}
.loading-text {
font-size: 28rpx;
color: #999;
}
.empty-image {
width: 200rpx;
height: 200rpx;
margin-bottom: 20rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
.message-item {
display: flex;
align-items: center;
padding: 24rpx 32rpx;
background-color: #fff;
border-bottom: 1rpx solid #f0f0f0;
&:active {
background-color: #f5f5f5;
}
}
.avatar-container {
position: relative;
margin-right: 24rpx;
}
.avatar {
width: 96rpx;
height: 96rpx;
border-radius: 8rpx;
}
.unread-badge {
position: absolute;
top: -8rpx;
right: -8rpx;
min-width: 32rpx;
height: 32rpx;
padding: 0 8rpx;
background-color: #ff4d4f;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
}
.unread-text {
font-size: 20rpx;
color: #fff;
line-height: 1;
}
.content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
min-width: 0;
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8rpx;
}
.name {
font-size: 32rpx;
font-weight: 500;
color: #333;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.time {
font-size: 24rpx;
color: #999;
margin-left: 16rpx;
flex-shrink: 0;
}
.message-preview {
display: flex;
align-items: center;
}
.preview-text {
font-size: 28rpx;
color: #999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.load-more {
padding: 20rpx 0;
text-align: center;
}
.load-more-text {
font-size: 24rpx;
color: #999;
}
</style>