feat(chat): 添加私信功能和WebSocket实时通信

- 集成WebSocket管理器,支持心跳、自动重连、消息队列
- 实现私信相关API接口,包括会话列表、历史消息、已读标记等
- 添加聊天页面和会话列表页面,支持实时消息收发
- 配置地图权限和腾讯地图SDK用于酒局定位功能
- 修改应用名称为"喝酒了么"并更新应用描述
- 在App.vue中初始化WebSocket连接和私信功能
- 添加详细的私信模块接口文档和Mock数据
- 优化单图片动态高度计算和预加载逻辑
This commit is contained in:
cg
2026-07-21 21:27:01 +08:00
parent 0332aabba0
commit eaa0d7101f
14 changed files with 2112 additions and 38 deletions
+80 -6
View File
@@ -2,7 +2,15 @@
<view :class="themeClass" class="page-container circle-page">
<!-- 顶部导航 -->
<view class="circle-header" :style="{ paddingTop: headerPaddingTop }">
<text class="circle-title">酒友圈</text>
<view class="circle-title-row" :style="{ paddingRight: headerPaddingRight }">
<text class="circle-title">酒友圈</text>
<view class="msg-entry" @click="goChatList">
<text class="msg-entry-icon">💬</text>
<view v-if="unreadTotal > 0" class="msg-badge">
<text class="msg-badge-text">{{ unreadTotal > 99 ? '99+' : unreadTotal }}</text>
</view>
</view>
</view>
<!-- Tab 切换 -->
<view class="circle-tabs">
<view
@@ -67,7 +75,7 @@
v-for="f in friends"
:key="f.id"
:friend="f"
@tap="goFriends"
@tap="goChat(f)"
/>
<EmptyState
v-if="!friends.length"
@@ -112,7 +120,7 @@ import FeedCard from '../../components/FeedCard.vue'
import FriendItem from '../../components/FriendItem.vue'
import EventCard from '../../components/EventCard.vue'
import EmptyState from '../../components/EmptyState.vue'
import { GetCircleFeeds, LikeFeed, UnlikeFeed, GetFriends, GetFriendRequests, GetEvents } from '../../common/api'
import { GetCircleFeeds, LikeFeed, UnlikeFeed, GetFriends, GetFriendRequests, GetEvents, GetUnreadCount } from '../../common/api'
import themeMixin from '../../common/theme-mixin'
export default {
@@ -120,10 +128,12 @@ export default {
components: { FeedCard, FriendItem, EventCard, EmptyState },
data() {
const menuBtn = uni.getMenuButtonBoundingClientRect()
const sysInfo = uni.getSystemInfoSync()
return {
tabs: ['动态', '酒友', '酒局'],
currentTab: 0,
headerPaddingTop: (menuBtn.top + 8) + 'px',
headerPaddingRight: (sysInfo.windowWidth - menuBtn.left + 8) + 'px',
// 动态
feeds: [],
page: 1,
@@ -134,13 +144,16 @@ export default {
friends: [],
friendRequests: [],
// 酒局
events: []
events: [],
// 私信未读
unreadTotal: 0
}
},
onShow() {
this.loadFeeds(true)
this.loadFriends()
this.loadEvents()
this.loadUnread()
},
methods: {
switchTab(i) {
@@ -212,6 +225,22 @@ export default {
goFriends() {
uni.navigateTo({ url: '/pages/friends/friends' })
},
goChat(friend) {
// 根据 friendId 查找对应会话 (f001 -> conv_001)
const convId = 'conv_' + friend.id.replace('f', '')
uni.navigateTo({
url: `/pages/chat/chat?friendId=${friend.id}&nickname=${encodeURIComponent(friend.nickname)}&conversationId=${convId}`
})
},
goChatList() {
uni.navigateTo({ url: '/pages/chat-list/chat-list' })
},
async loadUnread() {
try {
const res = await GetUnreadCount()
this.unreadTotal = res.data.total
} catch (e) { /* ignore */ }
},
// === 酒局 ===
async loadEvents() {
try {
@@ -256,12 +285,57 @@ export default {
z-index: 10;
}
.circle-title-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: $sp-lg;
}
.circle-title {
display: block;
font-size: $fs-2xl;
font-weight: $fw-black;
color: $text-primary;
margin-bottom: $sp-lg;
}
.msg-entry {
position: relative;
width: 72rpx;
height: 72rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: $bg-card;
&:active {
background: $bg-card-alt;
}
}
.msg-entry-icon {
font-size: 36rpx;
}
.msg-badge {
position: absolute;
top: -4rpx;
right: -4rpx;
min-width: 32rpx;
height: 32rpx;
padding: 0 8rpx;
border-radius: 16rpx;
background: $coral;
display: flex;
align-items: center;
justify-content: center;
}
.msg-badge-text {
font-size: 18rpx;
color: #fff;
font-weight: $fw-bold;
line-height: 1;
}
.circle-tabs {