<template>
|
<view class="chat-list-container">
|
<!-- 搜索框 -->
|
<view class="search-bar">
|
<view class="search-input">
|
<text class="iconfont icon-search"></text>
|
<input class="input" placeholder="搜索会话" v-model="searchKeyword" @input="onSearch">
|
</view>
|
</view>
|
|
<!-- 会话列表 -->
|
<scroll-view class="chat-list" scroll-y="true" @scrolltolower="loadMore">
|
<view class="list-container">
|
<!-- 加载状态 -->
|
<view class="loading" v-if="loading">
|
<text>加载中...</text>
|
</view>
|
|
<!-- 空状态 -->
|
<view class="empty" v-if="!loading && conversations.length === 0">
|
<image class="empty-icon" src="/static/icon/chat-empty.png" mode="aspectFit"></image>
|
<text class="empty-text">暂无聊天记录</text>
|
<text class="empty-tip">去名片页面开始聊天吧</text>
|
</view>
|
|
<!-- 会话列表 -->
|
<view class="conversation-item" v-for="conversation in conversations" :key="conversation.conversation_id"
|
@click="goToChat(conversation)">
|
<image class="avatar" :src="getConversationAvatar(conversation)" mode="aspectFill"></image>
|
|
<view class="content">
|
<view class="header">
|
<text class="name">{{ getConversationName(conversation) }}</text>
|
<text class="time">{{ formatTime(conversation.update_time) }}</text>
|
</view>
|
|
<view class="message">
|
<text class="text" v-if="conversation.last_message && conversation.last_message.length > 0">
|
{{ conversation.last_message[0].sender_id === currentUser.user_id ? '我: ' : '' }}{{ conversation.last_message[0].content }}
|
</text>
|
<text class="text" v-else>开始聊天</text>
|
</view>
|
</view>
|
|
<!-- 未读消息数量 -->
|
<view class="unread-badge" v-if="conversation.unread_count > 0">
|
<text class="unread-count">{{ conversation.unread_count > 99 ? '99+' : conversation.unread_count }}</text>
|
</view>
|
</view>
|
|
<!-- 加载更多 -->
|
<view class="load-more" v-if="hasMore && !loading">
|
<text class="load-text" @click="loadMore">加载更多</text>
|
</view>
|
|
<!-- 没有更多了 -->
|
<view class="no-more" v-if="!hasMore && conversations.length > 0">
|
<text class="no-more-text">没有更多了</text>
|
</view>
|
</view>
|
</scroll-view>
|
</view>
|
</template>
|
|
<script>
|
export default {
|
data() {
|
return {
|
// 用户信息
|
currentUser: {},
|
|
// 会话数据
|
conversations: [],
|
page: 1,
|
limit: 20,
|
hasMore: true,
|
loading: false,
|
|
// 搜索
|
searchKeyword: '',
|
searchTimer: null
|
};
|
},
|
onLoad() {
|
// 获取当前用户信息
|
this.getCurrentUser();
|
|
// 加载会话列表
|
this.loadConversations();
|
},
|
onShow() {
|
// 每次显示页面时重新加载会话列表,确保未读消息状态正确
|
this.loadConversations();
|
},
|
methods: {
|
// 获取当前用户信息
|
getCurrentUser() {
|
let self = this;
|
self._get('user.user/detail', {}, res => {
|
// 这里应该从全局状态或接口获取当前用户信息
|
self.currentUser = res.data.userInfo;
|
})
|
},
|
|
// 加载会话列表
|
loadConversations() {
|
if (this.loading) return;
|
|
this.loading = true;
|
|
let self = this;
|
self._get(
|
'plus.business.chat.chat/getConversations',
|
{
|
page: self.page,
|
limit: self.limit
|
},
|
function(res) {
|
self.loading = false;
|
if (res.code === 1) {
|
const conversationData = res.data.conversations || {};
|
const newConversations = conversationData.data || [];
|
|
if (self.page === 1) {
|
self.conversations = newConversations;
|
} else {
|
self.conversations = [...self.conversations, ...newConversations];
|
}
|
|
self.hasMore = self.conversations.length < (conversationData.total || 0);
|
self.page++;
|
}
|
}
|
);
|
},
|
|
// 加载更多
|
loadMore() {
|
if (this.hasMore && !this.loading) {
|
this.loadConversations();
|
}
|
},
|
|
// 搜索
|
onSearch() {
|
if (this.searchTimer) {
|
clearTimeout(this.searchTimer);
|
}
|
|
this.searchTimer = setTimeout(() => {
|
this.searchConversations();
|
}, 500);
|
},
|
|
// 搜索会话
|
searchConversations() {
|
if (!this.searchKeyword.trim()) {
|
this.page = 1;
|
this.loadConversations();
|
return;
|
}
|
|
let self = this;
|
self.loading = true;
|
|
// 暂时使用前端过滤
|
const filtered = self.conversations.filter(conv => {
|
const name = self.getConversationName(conv).toLowerCase();
|
const keyword = self.searchKeyword.toLowerCase();
|
return name.includes(keyword);
|
});
|
|
self.conversations = filtered;
|
self.hasMore = false;
|
self.loading = false;
|
},
|
|
// 跳转到聊天页面
|
goToChat(conversation) {
|
if (!conversation.businessCard) {
|
this.showError('会话信息不完整');
|
return;
|
}
|
|
// 获取目标用户信息
|
const targetUser = this.getTargetUser(conversation);
|
|
uni.navigateTo({
|
url: `/pages/plus/business/chat/chat?user_id=${targetUser.user_id}&business_card_id=${conversation.business_card_id}&nickName=${targetUser.nickName}`
|
});
|
},
|
|
// 获取会话头像
|
getConversationAvatar(conversation) {
|
if (conversation.businessCard && conversation.businessCard.avatar) {
|
return conversation.businessCard.avatar;
|
}
|
|
const targetUser = this.getTargetUser(conversation);
|
return targetUser.avatarUrl || '/static/default.png';
|
},
|
|
// 获取会话名称
|
getConversationName(conversation) {
|
if (conversation.businessCard) {
|
return conversation.businessCard.name || '用户';
|
}
|
|
const targetUser = this.getTargetUser(conversation);
|
return targetUser.nickName || '用户';
|
},
|
|
// 获取目标用户信息
|
getTargetUser(conversation) {
|
if (!conversation.participants) {
|
return { user_id: 0, nickName: '用户', avatarUrl: '/static/default.png' };
|
}
|
|
// 找到当前用户以外的参与者
|
const targetParticipant = conversation.participants.find(p =>
|
p.user_id !== this.currentUser.user_id && p.user
|
);
|
|
if (targetParticipant && targetParticipant.user) {
|
return {
|
user_id: targetParticipant.user_id,
|
nickName: targetParticipant.user.nickName || '用户',
|
avatarUrl: targetParticipant.user.avatarUrl || '/static/default.png'
|
};
|
}
|
|
return { user_id: 0, nickName: '用户', avatarUrl: '/static/default.png' };
|
},
|
|
// 格式化时间
|
formatTime(timeStr) {
|
if (!timeStr) return '';
|
|
// 处理字符串格式的时间
|
const date = new Date(timeStr);
|
const now = new Date();
|
|
// 今天的消息显示时间
|
if (date.toDateString() === now.toDateString()) {
|
return this.formatTimeOnly(date);
|
}
|
|
// 昨天的消息显示"昨天"
|
const yesterday = new Date(now);
|
yesterday.setDate(now.getDate() - 1);
|
if (date.toDateString() === yesterday.toDateString()) {
|
return `昨天 ${this.formatTimeOnly(date)}`;
|
}
|
|
// 一周内的消息显示星期几
|
const weekStart = new Date(now);
|
weekStart.setDate(now.getDate() - 6);
|
if (date > weekStart) {
|
const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
|
return `星期${weekDays[date.getDay()]}`;
|
}
|
|
// 其他时间显示完整日期
|
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
|
},
|
|
formatTimeOnly(date) {
|
const hours = date.getHours().toString().padStart(2, '0');
|
const minutes = date.getMinutes().toString().padStart(2, '0');
|
return `${hours}:${minutes}`;
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.chat-list-container {
|
display: flex;
|
flex-direction: column;
|
height: 100vh;
|
background-color: #f5f5f5;
|
}
|
|
// 搜索框样式
|
.search-bar {
|
background-color: #fff;
|
padding: 20rpx 30rpx;
|
border-bottom: 1rpx solid #e5e5e5;
|
|
.search-input {
|
display: flex;
|
align-items: center;
|
background: #f5f5f5;
|
border-radius: 10rpx;
|
padding: 15rpx 20rpx;
|
|
.iconfont {
|
font-size: 32rpx;
|
color: #999;
|
margin-right: 15rpx;
|
}
|
|
.input {
|
flex: 1;
|
font-size: 28rpx;
|
color: #333;
|
}
|
}
|
}
|
|
// 会话列表样式
|
.chat-list {
|
flex: 1;
|
|
.list-container {
|
min-height: 100%;
|
|
.loading, .empty {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 100rpx 0;
|
|
.empty-icon {
|
width: 200rpx;
|
height: 200rpx;
|
margin-bottom: 40rpx;
|
opacity: 0.5;
|
}
|
|
.empty-text {
|
font-size: 32rpx;
|
color: #999;
|
margin-bottom: 20rpx;
|
}
|
|
.empty-tip {
|
font-size: 28rpx;
|
color: #ccc;
|
}
|
}
|
|
.conversation-item {
|
display: flex;
|
align-items: center;
|
padding: 25rpx 30rpx;
|
background-color: #fff;
|
border-bottom: 1rpx solid #f5f5f5;
|
position: relative;
|
|
.avatar {
|
width: 100rpx;
|
height: 100rpx;
|
border-radius: 10rpx;
|
margin-right: 20rpx;
|
}
|
|
.content {
|
flex: 1;
|
min-width: 0;
|
|
.header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 10rpx;
|
|
.name {
|
font-size: 32rpx;
|
font-weight: bold;
|
color: #333;
|
max-width: 400rpx;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
}
|
|
.time {
|
font-size: 24rpx;
|
color: #999;
|
}
|
}
|
|
.message {
|
.text {
|
font-size: 28rpx;
|
color: #999;
|
max-width: 400rpx;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
}
|
}
|
}
|
|
.unread-badge {
|
position: absolute;
|
top: 25rpx;
|
right: 30rpx;
|
background: #ff3b30;
|
border-radius: 20rpx;
|
min-width: 40rpx;
|
height: 40rpx;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
padding: 0 10rpx;
|
|
.unread-count {
|
font-size: 24rpx;
|
color: #fff;
|
font-weight: bold;
|
}
|
}
|
}
|
|
.load-more, .no-more {
|
text-align: center;
|
padding: 30rpx 0;
|
|
.load-text, .no-more-text {
|
font-size: 28rpx;
|
color: #999;
|
}
|
|
.load-text {
|
color: #007aff;
|
}
|
}
|
}
|
}
|
</style>
|