|
|
@@ -8,67 +8,43 @@
|
|
|
</view>
|
|
|
|
|
|
<scroll-view scroll-y class="content">
|
|
|
- <!-- 系统通知 -->
|
|
|
- <view class="message-item system-notification active">
|
|
|
- <text class="message-type">系统通知</text>
|
|
|
- <text class="message-time">刚刚</text>
|
|
|
- <text class="message-content">您的线索审核已通过,获得20积分奖励,当前积分可兑换【资源查看权限】x1</text>
|
|
|
- <text class="message-footer">完成线索采集,积分+20 (距黄金级还差72分)</text>
|
|
|
+ <!-- 加载中 -->
|
|
|
+ <view v-if="loading" class="loading-container">
|
|
|
+ <text>加载中...</text>
|
|
|
</view>
|
|
|
-
|
|
|
- <!-- 撮合成功通知 -->
|
|
|
- <view class="message-item match-success">
|
|
|
- <view class="message-icon heart"></view>
|
|
|
- <view class="message-body">
|
|
|
- <text class="message-type">撮合成功通知</text>
|
|
|
- <text class="message-content">您推荐的王先生和刘女士已成功匹配,获得50积分+100元现金奖励</text>
|
|
|
- </view>
|
|
|
- <text class="message-time">10分钟前</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 今天分组 -->
|
|
|
- <view class="time-group">
|
|
|
- <text class="time-label">今天</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 魏先生消息 -->
|
|
|
- <view class="message-item user-message">
|
|
|
- <view class="message-avatar">魏</view>
|
|
|
- <view class="message-body">
|
|
|
- <text class="message-type">魏先生</text>
|
|
|
- <text class="message-content">您好,想了解一下李女士的详细情况,方便沟通吗?</text>
|
|
|
+
|
|
|
+ <!-- 会话列表 -->
|
|
|
+ <view v-else-if="conversationList.length > 0">
|
|
|
+ <view
|
|
|
+ v-for="conversation in conversationList"
|
|
|
+ :key="conversation.conversationID"
|
|
|
+ class="message-item user-message"
|
|
|
+ @click="openChat(conversation)"
|
|
|
+ >
|
|
|
+ <image
|
|
|
+ v-if="conversation.userProfile.avatar"
|
|
|
+ :src="conversation.userProfile.avatar"
|
|
|
+ class="message-avatar-img"
|
|
|
+ />
|
|
|
+ <view v-else class="message-avatar">
|
|
|
+ {{ conversation.userProfile.nick || conversation.userProfile.userID.charAt(0) }}
|
|
|
+ </view>
|
|
|
+ <view class="message-body">
|
|
|
+ <text class="message-type">{{ conversation.userProfile.nick || conversation.userProfile.userID }}</text>
|
|
|
+ <text class="message-content">{{ getLastMessageText(conversation.lastMessage) }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="message-right">
|
|
|
+ <text class="message-time">{{ formatTime(conversation.lastMessage.lastTime) }}</text>
|
|
|
+ <view v-if="conversation.unreadCount > 0" class="unread-badge">
|
|
|
+ {{ conversation.unreadCount > 99 ? '99+' : conversation.unreadCount }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <text class="message-time">1小时前</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 昨日分组 -->
|
|
|
- <view class="time-group">
|
|
|
- <text class="time-label">昨日</text>
|
|
|
</view>
|
|
|
-
|
|
|
- <!-- 张先生消息 -->
|
|
|
- <view class="message-item user-message">
|
|
|
- <view class="message-avatar">张</view>
|
|
|
- <view class="message-body">
|
|
|
- <text class="message-type">张先生</text>
|
|
|
- <text class="message-content">您好,想了解一下王女士的详细情况,方便沟通吗?</text>
|
|
|
- </view>
|
|
|
- <text class="message-time">1小时前</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 更早分组 -->
|
|
|
- <view class="time-group">
|
|
|
- <text class="time-label">更早</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 高先生消息 -->
|
|
|
- <view class="message-item user-message">
|
|
|
- <view class="message-avatar">高</view>
|
|
|
- <view class="message-body">
|
|
|
- <text class="message-type">高先生</text>
|
|
|
- <text class="message-content">您好,想了解一下陈女士的详细情况,方便沟通吗?</text>
|
|
|
- </view>
|
|
|
- <text class="message-time">1小时前</text>
|
|
|
+
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <view v-else class="empty-container">
|
|
|
+ <text>暂无消息</text>
|
|
|
</view>
|
|
|
</scroll-view>
|
|
|
|
|
|
@@ -101,65 +77,245 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+ import timManager from '@/utils/tim.js'
|
|
|
+ import TIM from '@/utils/tim-wx-sdk.js'
|
|
|
+
|
|
|
export default {
|
|
|
data() {
|
|
|
return {
|
|
|
- messages: [
|
|
|
- {
|
|
|
- id: 1,
|
|
|
- type: 'system',
|
|
|
- title: '系统通知',
|
|
|
- content: '您的线索审核已通过,获得20积分奖励,当前积分可兑换【资源查看权限】x1',
|
|
|
- footer: '完成线索采集,积分+20 (距黄金级还差72分)',
|
|
|
- time: '刚刚',
|
|
|
- isNew: true
|
|
|
- },
|
|
|
- {
|
|
|
- id: 2,
|
|
|
- type: 'matchSuccess',
|
|
|
- title: '撮合成功通知',
|
|
|
- content: '您推荐的王先生和刘女士已成功匹配,获得50积分+100元现金奖励',
|
|
|
- time: '10分钟前',
|
|
|
- isNew: false
|
|
|
- },
|
|
|
- {
|
|
|
- id: 3,
|
|
|
- type: 'user',
|
|
|
- title: '王先生',
|
|
|
- content: '您好,想了解一下李女士的详细情况,方便沟通吗?',
|
|
|
- time: '1小时前',
|
|
|
- isNew: false
|
|
|
- }
|
|
|
- ]
|
|
|
+ loading: true,
|
|
|
+ conversationList: [],
|
|
|
+ matchmakerInfo: null,
|
|
|
+ imUserId: '',
|
|
|
+ totalUnreadCount: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async onLoad() {
|
|
|
+ await this.initIM()
|
|
|
+ },
|
|
|
+
|
|
|
+ onShow() {
|
|
|
+ // 页面显示时刷新会话列表
|
|
|
+ if (this.imUserId) {
|
|
|
+ this.loadConversationList()
|
|
|
}
|
|
|
},
|
|
|
+
|
|
|
+ onUnload() {
|
|
|
+ // 页面卸载时移除监听
|
|
|
+ this.removeListeners()
|
|
|
+ },
|
|
|
+
|
|
|
methods: {
|
|
|
+ // 初始化 IM
|
|
|
+ async initIM() {
|
|
|
+ try {
|
|
|
+ this.loading = true
|
|
|
+
|
|
|
+ // 1. 获取当前登录用户ID
|
|
|
+ const userId = uni.getStorageSync('userId')
|
|
|
+ if (!userId) {
|
|
|
+ uni.showToast({ title: '请先登录', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 获取红娘信息
|
|
|
+ const res = await uni.request({
|
|
|
+ url: 'http://localhost:8081/api/matchmaker/current',
|
|
|
+ method: 'GET',
|
|
|
+ data: { userId }
|
|
|
+ })
|
|
|
+
|
|
|
+ if (res[1].data.code !== 200) {
|
|
|
+ uni.showToast({ title: '获取红娘信息失败', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ this.matchmakerInfo = res[1].data.data
|
|
|
+ this.imUserId = this.matchmakerInfo.imUserId // m_1
|
|
|
+
|
|
|
+ console.log('✅ 红娘信息:', this.matchmakerInfo)
|
|
|
+
|
|
|
+ // 3. 获取 UserSig
|
|
|
+ const sigRes = await uni.request({
|
|
|
+ url: `http://localhost:1004/api/im/getUserSig?userId=${this.imUserId}`,
|
|
|
+ method: 'GET'
|
|
|
+ })
|
|
|
+
|
|
|
+ if (sigRes[1].data.code !== 200) {
|
|
|
+ uni.showToast({ title: '获取UserSig失败', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const userSig = sigRes[1].data.data
|
|
|
+ console.log('✅ 获取到 UserSig')
|
|
|
+
|
|
|
+ // 4. 登录 IM
|
|
|
+ await timManager.login(this.imUserId, userSig)
|
|
|
+ console.log('✅ 红娘已登录 IM:', this.imUserId)
|
|
|
+
|
|
|
+ // 5. 监听事件
|
|
|
+ this.addListeners()
|
|
|
+
|
|
|
+ // 6. 加载会话列表
|
|
|
+ await this.loadConversationList()
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 初始化 IM 失败:', error)
|
|
|
+ uni.showToast({ title: '初始化失败', icon: 'none' })
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载会话列表
|
|
|
+ async loadConversationList() {
|
|
|
+ try {
|
|
|
+ const tim = timManager.getTim()
|
|
|
+ const { data } = await tim.getConversationList()
|
|
|
+ this.conversationList = data.conversationList
|
|
|
+
|
|
|
+ // 计算总未读数
|
|
|
+ this.totalUnreadCount = this.conversationList.reduce((total, conv) => {
|
|
|
+ return total + conv.unreadCount
|
|
|
+ }, 0)
|
|
|
+
|
|
|
+ console.log('✅ 会话列表:', this.conversationList)
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 加载会话列表失败:', error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 添加事件监听
|
|
|
+ addListeners() {
|
|
|
+ const tim = timManager.getTim()
|
|
|
+
|
|
|
+ // 监听新消息
|
|
|
+ tim.on(TIM.EVENT.MESSAGE_RECEIVED, this.onMessageReceived)
|
|
|
+
|
|
|
+ // 监听会话列表更新
|
|
|
+ tim.on(TIM.EVENT.CONVERSATION_LIST_UPDATED, this.onConversationListUpdated)
|
|
|
+ },
|
|
|
+
|
|
|
+ // 移除事件监听
|
|
|
+ removeListeners() {
|
|
|
+ const tim = timManager.getTim()
|
|
|
+ tim.off(TIM.EVENT.MESSAGE_RECEIVED, this.onMessageReceived)
|
|
|
+ tim.off(TIM.EVENT.CONVERSATION_LIST_UPDATED, this.onConversationListUpdated)
|
|
|
+ },
|
|
|
+
|
|
|
+ // 收到新消息
|
|
|
+ onMessageReceived(event) {
|
|
|
+ console.log('📩 收到新消息:', event.data)
|
|
|
+ // 刷新会话列表
|
|
|
+ this.loadConversationList()
|
|
|
+ },
|
|
|
+
|
|
|
+ // 会话列表更新
|
|
|
+ onConversationListUpdated(event) {
|
|
|
+ console.log('🔄 会话列表更新:', event.data)
|
|
|
+ this.conversationList = event.data
|
|
|
+
|
|
|
+ // 更新总未读数
|
|
|
+ this.totalUnreadCount = this.conversationList.reduce((total, conv) => {
|
|
|
+ return total + conv.unreadCount
|
|
|
+ }, 0)
|
|
|
+ },
|
|
|
+
|
|
|
+ // 打开聊天页面
|
|
|
+ openChat(conversation) {
|
|
|
+ const targetUserId = conversation.userProfile.userID
|
|
|
+ uni.navigateTo({
|
|
|
+ url: `/pages/message/chat?targetUserId=${targetUserId}&fromMatchmaker=true`
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取最后一条消息的文本
|
|
|
+ getLastMessageText(lastMessage) {
|
|
|
+ if (!lastMessage) return ''
|
|
|
+
|
|
|
+ switch (lastMessage.type) {
|
|
|
+ case TIM.TYPES.MSG_TEXT:
|
|
|
+ return lastMessage.payload.text
|
|
|
+ case TIM.TYPES.MSG_IMAGE:
|
|
|
+ return '[图片]'
|
|
|
+ case TIM.TYPES.MSG_AUDIO:
|
|
|
+ return '[语音]'
|
|
|
+ case TIM.TYPES.MSG_VIDEO:
|
|
|
+ return '[视频]'
|
|
|
+ case TIM.TYPES.MSG_FILE:
|
|
|
+ return '[文件]'
|
|
|
+ default:
|
|
|
+ return '[消息]'
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 格式化时间
|
|
|
+ formatTime(timestamp) {
|
|
|
+ if (!timestamp) return ''
|
|
|
+
|
|
|
+ const now = new Date()
|
|
|
+ const msgTime = new Date(timestamp * 1000)
|
|
|
+ const diff = now - msgTime
|
|
|
+
|
|
|
+ // 一分钟内
|
|
|
+ if (diff < 60000) {
|
|
|
+ return '刚刚'
|
|
|
+ }
|
|
|
+
|
|
|
+ // 一小时内
|
|
|
+ if (diff < 3600000) {
|
|
|
+ return Math.floor(diff / 60000) + '分钟前'
|
|
|
+ }
|
|
|
+
|
|
|
+ // 今天
|
|
|
+ if (msgTime.toDateString() === now.toDateString()) {
|
|
|
+ return msgTime.getHours() + ':' + String(msgTime.getMinutes()).padStart(2, '0')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 昨天
|
|
|
+ const yesterday = new Date(now)
|
|
|
+ yesterday.setDate(yesterday.getDate() - 1)
|
|
|
+ if (msgTime.toDateString() === yesterday.toDateString()) {
|
|
|
+ return '昨天'
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更早
|
|
|
+ return (msgTime.getMonth() + 1) + '-' + msgTime.getDate()
|
|
|
+ },
|
|
|
+
|
|
|
// 返回上一页
|
|
|
goBack() {
|
|
|
uni.navigateBack()
|
|
|
},
|
|
|
+
|
|
|
// 导航到工作台
|
|
|
navigateToWorkbench() {
|
|
|
uni.redirectTo({
|
|
|
url: '/pages/matchmaker-workbench/index'
|
|
|
})
|
|
|
},
|
|
|
+
|
|
|
// 导航到我的资源
|
|
|
navigateToMyResources() {
|
|
|
uni.redirectTo({
|
|
|
url: '/pages/matchmaker-workbench/my-resources'
|
|
|
})
|
|
|
},
|
|
|
+
|
|
|
// 导航到排行榜
|
|
|
navigateToRanking() {
|
|
|
uni.redirectTo({
|
|
|
url: '/pages/matchmaker-workbench/ranking'
|
|
|
})
|
|
|
},
|
|
|
+
|
|
|
// 导航到消息
|
|
|
navigateToMessage() {
|
|
|
// 已在消息页面,无需跳转
|
|
|
},
|
|
|
+
|
|
|
// 导航到我的
|
|
|
navigateToMine() {
|
|
|
uni.redirectTo({
|
|
|
@@ -317,6 +473,7 @@
|
|
|
display: flex;
|
|
|
background: #FFFFFF;
|
|
|
border: 2rpx solid #E0E0E0;
|
|
|
+ align-items: center;
|
|
|
|
|
|
.message-avatar {
|
|
|
width: 60rpx;
|
|
|
@@ -330,10 +487,20 @@
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
margin-right: 20rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .message-avatar-img {
|
|
|
+ width: 60rpx;
|
|
|
+ height: 60rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 20rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.message-body {
|
|
|
flex: 1;
|
|
|
+ min-width: 0;
|
|
|
}
|
|
|
|
|
|
.message-type {
|
|
|
@@ -349,15 +516,46 @@
|
|
|
font-size: 26rpx;
|
|
|
color: #666;
|
|
|
line-height: 1.4;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .message-right {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-end;
|
|
|
+ margin-left: 20rpx;
|
|
|
}
|
|
|
|
|
|
.message-time {
|
|
|
font-size: 24rpx;
|
|
|
color: #999;
|
|
|
- margin-top: auto;
|
|
|
+ margin-bottom: 10rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .unread-badge {
|
|
|
+ background: #E91E63;
|
|
|
+ color: #FFFFFF;
|
|
|
+ font-size: 20rpx;
|
|
|
+ padding: 4rpx 10rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ min-width: 36rpx;
|
|
|
+ text-align: center;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /* 加载和空状态 */
|
|
|
+ .loading-container,
|
|
|
+ .empty-container {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ padding: 100rpx 0;
|
|
|
+ color: #999;
|
|
|
+ font-size: 28rpx;
|
|
|
+ }
|
|
|
|
|
|
/* 时间分组 */
|
|
|
.time-group {
|