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
+69 -15
View File
@@ -166,10 +166,18 @@
<view class="dice-cup" :class="{ 'cup-shaking': diceShaking }" @click="diceRoll">
<view class="dice-pair">
<view class="die" :class="{ 'die-rolling': diceShaking }">
<text class="die-face">{{ diceShaking ? '?' : diceFaces[diceA] }}</text>
<view class="die-grid">
<view class="die-cell" v-for="p in 9" :key="p">
<view class="die-pip" v-if="dicePips(diceA).indexOf(p) > -1"></view>
</view>
</view>
</view>
<view class="die die-2" :class="{ 'die-rolling': diceShaking }">
<text class="die-face">{{ diceShaking ? '?' : diceFaces[diceB] }}</text>
<view class="die-grid">
<view class="die-cell" v-for="p in 9" :key="p">
<view class="die-pip" v-if="dicePips(diceB).indexOf(p) > -1"></view>
</view>
</view>
</view>
</view>
<text class="dice-sum text-num" v-if="!diceShaking && diceRound > 0">{{ diceA + diceB }}</text>
@@ -213,7 +221,9 @@
:key="i"
:class="{ 'slot-item-active': !wheelSpinning && wheelResult && i === slotTarget }"
>
<text class="slot-item-emoji">{{ s.emoji }}</text>
<view class="slot-item-emoji-box">
<text class="slot-item-emoji">{{ s.emoji }}</text>
</view>
<text class="slot-item-label">{{ s.label }}</text>
</view>
</view>
@@ -299,7 +309,6 @@ export default {
rpsLastPick: '',
rpsTimer: null,
// --- 骰子 ---
diceFaces: ['', '⚀', '⚁', '⚂', '⚃', '⚄', '⚅'],
diceA: 1,
diceB: 1,
diceShaking: false,
@@ -452,6 +461,18 @@ export default {
},
/* ========== 骰子大话 ========== */
// 骰子点数对应的 pip 位置(3x3 九宫格,1~9 从左到右、从上到下)
dicePips(val) {
const map = {
1: [5],
2: [1, 9],
3: [1, 5, 9],
4: [1, 3, 7, 9],
5: [1, 3, 5, 7, 9],
6: [1, 3, 4, 6, 7, 9]
}
return map[val] || []
},
diceRoll() {
if (this.diceShaking) return
this.diceShaking = true
@@ -716,14 +737,14 @@ export default {
.rule-title {
display: block;
font-size: $fs-sm;
font-size: 30rpx;
font-weight: $fw-bold;
color: $text-secondary;
margin-bottom: $sp-sm;
}
.rule-text {
font-size: $fs-xs;
font-size: 30rpx;
color: $text-tertiary;
line-height: $lh-loose;
}
@@ -784,7 +805,7 @@ export default {
background: linear-gradient(135deg, var(--amber, #E8A838), var(--amber-deep, #C47F17));
box-shadow: var(--shadow-amber, 0 8rpx 32rpx rgba(232,168,56,0.25));
transition: transform $duration-fast $ease-out, opacity $duration-fast;
text { color: var(--text-on-amber, #0B0B14); font-size: $fs-base; font-weight: $fw-bold; }
text { color: var(--text-on-amber, #0B0B14); font-size:40rpx; font-weight: $fw-bold; }
&:active { transform: scale(0.94); }
&.btn-disabled { opacity: 0.5; pointer-events: none; }
}
@@ -1069,11 +1090,12 @@ export default {
}
.die {
width: 120rpx; height: 120rpx;
display: flex; align-items: center; justify-content: center;
width: 132rpx; height: 132rpx;
display: flex;
align-items: center; justify-content: center;
border-radius: $radius-md;
background: $bg-elevated;
border: 2rpx solid var(--border-subtle, rgba(255,255,255,0.10));
background: linear-gradient(160deg, #FBF7EF, #EAE2D3);
box-shadow: inset 0 4rpx 8rpx rgba(255,255,255,0.7), inset 0 -6rpx 12rpx rgba(0,0,0,0.12), $shadow-sm;
transition: transform $duration-base $ease-bounce;
&.die-rolling { animation: die-spin 0.3s linear infinite; }
@@ -1085,7 +1107,28 @@ export default {
100% { transform: rotate(360deg) scale(1); }
}
.die-face { font-size: 72rpx; color: $text-primary; }
.die-grid {
display: flex;
flex-wrap: wrap;
width: 96rpx;
height: 96rpx;
}
.die-cell {
width: 32rpx;
height: 32rpx;
display: flex;
align-items: center;
justify-content: center;
}
.die-pip {
width: 18rpx;
height: 18rpx;
border-radius: 50%;
background: #241B10;
box-shadow: inset 0 2rpx 3rpx rgba(0,0,0,0.5);
}
.dice-sum {
font-size: $fs-2xl;
@@ -1199,6 +1242,7 @@ export default {
position: absolute;
left: 0; right: 0;
top: 0;
width: 100%;
will-change: transform;
}
@@ -1206,7 +1250,7 @@ export default {
display: flex;
align-items: center;
justify-content: center;
gap: $sp-md;
gap: $sp-sm;
height: 120rpx;
border-bottom: 1rpx solid var(--border-micro, rgba(255,255,255,0.05));
transition: background $duration-base;
@@ -1216,8 +1260,18 @@ export default {
}
}
.slot-item-emoji { font-size: 44rpx; }
.slot-item-label { font-size: $fs-base; font-weight: $fw-bold; color: $text-primary; }
.slot-item-emoji-box {
width: 52rpx;
height: 52rpx;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
flex-shrink: 0;
}
.slot-item-emoji { font-size: 40rpx; line-height: 1; }
.slot-item-label { font-size: $fs-base; font-weight: $fw-bold; color: $text-primary; letter-spacing: 2rpx; }
.slot-mask-top, .slot-mask-bottom {
position: absolute;