@aochuang/client-sdk 1.0.367 → 1.0.369
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/services/client-chat/client-chat-wechat/client-chat-account.js +57 -14
- package/services/client-chat/client-chat-wechat/client-chat-session.js +23 -4
- package/services/client-chat/client-chat-wechat/client-chat-socket.js +5 -1
- package/services/client-chat/client-chat-wechat/client-chat.js +108 -56
- package/services/client-chat/client-chat-wechat/docs//350/264/246/345/217/267/346/234/252/350/257/273/346/225/260/351/207/217/344/270/216/344/274/232/350/257/235/346/234/252/350/257/273/346/225/260/351/207/217/344/270/215/344/270/200/350/207/264/351/227/256/351/242/230/344/277/256/345/244/215.md +296 -0
- package/services/socket/socket.js +9 -5
- package/utils/log.js +579 -220
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# 工作微信号未读数量与会话未读数量不一致问题修复
|
|
2
|
+
|
|
3
|
+
- 日期:2026-09-29
|
|
4
|
+
- 涉及文件:
|
|
5
|
+
- `services/client-chat/client-chat-wechat/client-chat.js`
|
|
6
|
+
- `services/client-chat/client-chat-wechat/client-chat-session.js`
|
|
7
|
+
- `services/client-chat/client-chat-wechat/client-chat-account.js`
|
|
8
|
+
- 相关提交:`2679dd9`(A2 / A4 / B1 / D),A1 为后续单独提交
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. 问题现象
|
|
13
|
+
|
|
14
|
+
客户端左侧工作微信号徽标显示有未读(例如 8),但右侧"最近会话"里除免打扰会话外已经没有任何未读会话;刷新页面后,从服务端重新拉取的账号未读数量为 0。
|
|
15
|
+
|
|
16
|
+
即:**本地账号未读数 > 服务端账号未读数,且本地会话未读之和为 0**。
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2. 根因分析
|
|
21
|
+
|
|
22
|
+
SDK 里维护着两套彼此独立的本地"账本":
|
|
23
|
+
|
|
24
|
+
| 账本 | 初始值 | 增量维护 |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| 账号未读数(`account.accountUnreadMessageNumData`) | 登录时 `getAccountUnreadMessageNumMethod`,服务端按该账号**所有会话**(不管本地是否加载)计算 | 本地 ±N |
|
|
27
|
+
| 会话未读数(`session.sessionMap[id].unreadMsgCount`) | 分页拉会话列表时服务端给的 | 本地 ±1 |
|
|
28
|
+
|
|
29
|
+
账号未读数只有两处减法,都是按**本地会话**的 `unreadMsgCount` 减:
|
|
30
|
+
|
|
31
|
+
- `onSessionReadChange`:会话被标记已读
|
|
32
|
+
- `onRemoveSession`:会话被移除
|
|
33
|
+
|
|
34
|
+
所以,凡是"加到账号上的数,没有等量落到某个本地会话的 `unreadMsgCount` 上"的路径,都会在账号上留下永远减不掉的残数。再加上所有减法都用了 `Math.max(0, …)` 钳位,少算的被抹平、多算的一直留着,长期运行必然表现为"本地 ≥ 服务端,刷新归零"。
|
|
35
|
+
|
|
36
|
+
本次排查出的具体路径:
|
|
37
|
+
|
|
38
|
+
### 2.1 新消息触发 `getSession` 时,把服务端存量未读整个加到账号(主因)
|
|
39
|
+
|
|
40
|
+
场景:某会话本地还没分页加载到(一个号几百个会话很常见),来了一条新消息 → `findSession` 找不到 → `getSession` 从服务端拉回 → `addSession(rs.data, null)` → `onAddSession` 把服务端返回的 `unreadMsgCount`(存量 k + 新增 1)**整个**加到账号。
|
|
41
|
+
|
|
42
|
+
而账号初始值里已经含了这 k 条存量,于是多算了 k。用户点开该会话只减 k+1,账号永久多出 k。
|
|
43
|
+
|
|
44
|
+
举例:会话 C 服务端存量 5、本地未加载,账号初始值 10。来 1 条新消息:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
服务端:C 未读 6,账号 11
|
|
48
|
+
本地: C 未读 6,账号 10 + 6 = 16 ← 多了 5
|
|
49
|
+
点开 C:账号 16 - 6 = 10,实际应为 5,再点完其他会话后本地剩 5、服务端 0
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2.2 分配会话(`CmdFriendInfoChanged` / `CmdChatroomInfoChanged` changeType=4)重复累加两次
|
|
53
|
+
|
|
54
|
+
`loadAssignTaskSessionData` 内部 `setSessionData(rs, null, false)` → `addSession(item, null)` → `onAddSession` 累加一次;外层 `.then` 回调里又对同一批 `rs` 手动 `updateAccountUnreadMessageNum` 累加一次。有未读的分配会话账号直接翻倍,点开只减一半。
|
|
55
|
+
|
|
56
|
+
### 2.3 本地未加载到的会话被服务端删除 / 转移,本地无法扣减
|
|
57
|
+
|
|
58
|
+
好友转移(changeType=4 且 `friends[].changeType === 3`)、删除好友(changeType=3)、群聊同理。服务端会把账号未读减 k;本地走 `removeSession` 时 `sessionMap` 里没有它,直接 return,账号不减。这个会话从未在本地列表出现过(所以看起来"全部已读"),账号却多 k。
|
|
59
|
+
|
|
60
|
+
### 2.4 断线重连后没有校准
|
|
61
|
+
|
|
62
|
+
重连本身不会单独制造偏差(补拉消息是成对累加的),但断线期间是偏差最容易堆积的时刻(手机端很可能处理了消息),且重连是天然的"该对账了"信号,此前没有利用。
|
|
63
|
+
|
|
64
|
+
### 2.5 缺少排查手段
|
|
65
|
+
|
|
66
|
+
账号未读数量的每次变化没有日志,拿到客户日志也无法定位是哪条路径漂的。
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 3. 修复内容
|
|
71
|
+
|
|
72
|
+
### A1. `getSession` 路径账号只累加"本次新增"条数
|
|
73
|
+
|
|
74
|
+
**client-chat-session.js**
|
|
75
|
+
|
|
76
|
+
- `getSession` 的轮询合并 `context` 新增 `accountUnreadDelta: 0`(第 329 行附近),并在"会话轮询合并完成"日志里输出
|
|
77
|
+
- `addSession(data, wechatAccountId, options = {})` 新增第三个参数,`options.unreadDelta` 透传给 `onAddSession`(第 508 行)
|
|
78
|
+
- 合并完成后 `addSession(rs.data, null, { unreadDelta: context.accountUnreadDelta })`(第 343 行)
|
|
79
|
+
|
|
80
|
+
**client-chat.js**
|
|
81
|
+
|
|
82
|
+
- 好友 / 群聊两处 `getSession` 的 serialize 回调(第 486 / 636 行附近):
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
// 会话未读:只在服务端没算过这条消息时 +1(原逻辑不变)
|
|
86
|
+
if (!data.isSend && isAfterServerMessage) { ... }
|
|
87
|
+
// 账号未读:不管是否被 skip 都 +1,只有"正在看当前会话被直接标记已读"不加
|
|
88
|
+
if (!data.isSend && !(isAfterServerMessage && isCurrentSessionRead)) {
|
|
89
|
+
context.accountUnreadDelta += 1
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
注意 `accountUnreadDelta` **不等于** `unreadMessageIds.length`:被 skip 的消息表示服务端返回的会话已经把它算进 `unreadMsgCount`,但账号初始值是登录时取的,仍然不含这条,所以账号还是要 +1。
|
|
94
|
+
|
|
95
|
+
- `onAddSession`(第 132 行附近):
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
const delta = typeof unreadDelta === 'number' ? unreadDelta : (session.unreadMsgCount || 0)
|
|
99
|
+
if (delta > 0) { 账号 += delta }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- `unreadDelta` 是数字 → `getSession` 来源 → 只加新增(日志 source:`onAddSession:getSession`)
|
|
103
|
+
- `unreadDelta` 为 `undefined` → 分配等来源 → 整个 `unreadMsgCount` 加上(原逻辑,日志 source:`onAddSession`)
|
|
104
|
+
- 分页来源(有 `wechatAccountId`)不加,原逻辑不变
|
|
105
|
+
|
|
106
|
+
副带收益:`addSession` 的 `isRefreshAll` 路径(会话已存在时又被 `getSession` 拉回)以前也会整量重复累加,现在只加 delta。
|
|
107
|
+
|
|
108
|
+
### A2. 去掉分配会话的重复累加
|
|
109
|
+
|
|
110
|
+
**client-chat.js** `onCmdFriendInfoChanged` / `onCmdChatroomInfoChanged` 的 `changeType === 4` 分支:删掉外层 `.then` 里对 `rs` 逐个 `updateAccountUnreadMessageNum(+unreadMsgCount)` 的两段代码,累加只保留 `onAddSession` 这一个入口。
|
|
111
|
+
|
|
112
|
+
### A4. 删除 / 转移后以服务端为准刷新账号未读
|
|
113
|
+
|
|
114
|
+
**client-chat.js** 新增方法:
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
refreshAccountsUnreadMessageNum (wechatAccountIds) // 第 1251 行附近
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
对 id 去重、过滤掉不在 `accountMap` 中的账号后,逐个调用 `account.refreshAccountUnreadMessageNum({ wechatAccountId })`。
|
|
121
|
+
|
|
122
|
+
调用位置:
|
|
123
|
+
|
|
124
|
+
| 位置 | 传入的账号 |
|
|
125
|
+
|---|---|
|
|
126
|
+
| 好友 changeType=4,`ps.finally` 内(`reloadData` 之后) | `rs` 中的账号 ∪ `data.wechatAccountIds` |
|
|
127
|
+
| 好友 changeType=3 | `data.wechatAccountIds` |
|
|
128
|
+
| 群聊 changeType=4,`ps.finally` 内 | `rs` 中的账号 ∪ `data.wechatAccountIds` |
|
|
129
|
+
| 群聊 changeType=3 | `data.wechatAccountIds` |
|
|
130
|
+
|
|
131
|
+
本地没有会话数据时增量是做不了的,只能靠服务端对账。
|
|
132
|
+
|
|
133
|
+
### B1. 重连后全量校准
|
|
134
|
+
|
|
135
|
+
**client-chat.js** `onSocketOpen`(第 1191 行附近):`loadLossMessageData` 补拉完成后调用 `account.refreshAllAccountUnreadMesageNum()`。加了 `if (ps.length)` 判断,首次连接(没有 `lastReceiveMessageTime`)不会多刷,因为登录时 `onAccountAdded` 已经拉过。
|
|
136
|
+
|
|
137
|
+
### D. 排查日志
|
|
138
|
+
|
|
139
|
+
**client-chat-account.js**
|
|
140
|
+
|
|
141
|
+
- 新增配置项 `onUnreadMessageNumLog` 和 `_addUnreadMessageNumLog(title, data)`,日志 group:`client-chat-account:unreadMessageNum`
|
|
142
|
+
- `updateAccountUnreadMessageNum(accountId, callback, source)` 新增第三个参数 `source`(可选),数值有变化时记录:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"source": "onNewFriendMessage",
|
|
147
|
+
"wechatAccountId": "...",
|
|
148
|
+
"before": { "num": 10, "muteNum": 2 },
|
|
149
|
+
"after": { "num": 11, "muteNum": 2 },
|
|
150
|
+
"delta": { "num": 1, "muteNum": 0 },
|
|
151
|
+
"localSessionUnread": { "num": 11, "muteNum": 2 }
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
- `refreshAccountUnreadMessageNum` / `refreshAllAccountUnreadMesageNum` 也各记一条(source:`refresh` / `refreshAll`,带 before / after),用于观察服务端值和本地值差多少
|
|
156
|
+
|
|
157
|
+
**client-chat.js**
|
|
158
|
+
|
|
159
|
+
- 五个本地增量调用点打上 source:`onAddSession`、`onAddSession:getSession`、`onRemoveSession`、`onSessionReadChange`、`onNewFriendMessage`、`onNewRoomMessage`
|
|
160
|
+
- 注入 `onUnreadMessageNumLog` 时(第 793 行附近),额外计算该账号在 `session.sessionMap` 中本地会话未读之和 `localSessionUnread`,一起写进日志后交给 `socket.addLog`
|
|
161
|
+
|
|
162
|
+
日志受 `socket.logEnable` 控制,关闭时零开销;存储走现有 3MB 上限自动淘汰。
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 4. 如何用日志定位问题
|
|
167
|
+
|
|
168
|
+
1. 导出客户端日志,过滤 group 为 `client-chat-account:unreadMessageNum`
|
|
169
|
+
2. 逐条对比 `after.num` 与 `localSessionUnread.num`:
|
|
170
|
+
- 两者相等:账号和本地会话是配平的
|
|
171
|
+
- `after.num > localSessionUnread.num` 且此后一直不回落:从这条开始漂了,看 `source` 即可知道是哪条路径
|
|
172
|
+
3. 对比 `source: refresh` 的 `before` / `after`:差值就是当时本地相对服务端的累计偏差
|
|
173
|
+
4. 结合 `client-chat-session:getSession` 里"会话轮询合并完成"的 `accountUnreadDelta` / `unreadMessageCount` / `skippedMessageCount`,可以验证 A1 的增量是否正确
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 5. 测试场景
|
|
178
|
+
|
|
179
|
+
### 5.1 测试前准备
|
|
180
|
+
|
|
181
|
+
- 打开 SDK 日志(`socket.logEnable = true`),测试过程中随时导出日志按 group 过滤
|
|
182
|
+
- 准备一个有较多会话的工作微信号(至少能分 3 页以上),下文称账号 X
|
|
183
|
+
- 准备"对照值"获取方式:刷新页面后左侧徽标显示的就是服务端值;或直接调 `getAccountUnreadMessageNumMethod`
|
|
184
|
+
- 每个场景通用验收标准:
|
|
185
|
+
1. 操作过程中左侧账号徽标 = 右侧该账号本地会话未读之和(免打扰会话单独算 `muteNum`)
|
|
186
|
+
2. 把所有会话点开读完后,账号徽标归 0
|
|
187
|
+
3. 刷新页面后徽标值不变(本地 = 服务端)
|
|
188
|
+
4. 日志中每条 `client-chat-account:unreadMessageNum` 的 `after.num` 与 `localSessionUnread.num` 相等
|
|
189
|
+
|
|
190
|
+
### 5.2 A1:本地未加载的会话收到新消息
|
|
191
|
+
|
|
192
|
+
| 步骤 | 预期 |
|
|
193
|
+
|---|---|
|
|
194
|
+
| 1. 让账号 X 的某个会话 C 积累 k 条未读(例如 3 条),并确保 C 排在会话列表第 3 页之后(用其他会话把它往下压) | — |
|
|
195
|
+
| 2. 登录客户端,只加载第 1 页,记录账号 X 徽标值 N(其中已含 C 的 3 条) | 徽标 = N |
|
|
196
|
+
| 3. 用 C 对应的微信给账号 X 发 1 条消息 | 会话 C 出现在列表顶部,未读 4;账号徽标 = **N + 1**(修复前是 N + 4) |
|
|
197
|
+
| 4. 查日志 `client-chat-session:getSession` 的"会话轮询合并完成" | `accountUnreadDelta: 1`;如果服务端返回的会话已含这条消息则 `skippedMessageCount: 1, unreadMessageCount: 0`,否则反过来,但 `accountUnreadDelta` 都是 1 |
|
|
198
|
+
| 5. 查日志 `client-chat-account:unreadMessageNum` | 有一条 `source: "onAddSession:getSession"`,`delta.num: 1` |
|
|
199
|
+
| 6. 点开 C | 账号徽标 = N - 3;`source: "onSessionReadChange"`,`delta.num: -4` |
|
|
200
|
+
| 7. 把账号 X 其余会话全部点开 | 徽标归 0;刷新后仍为 0 |
|
|
201
|
+
|
|
202
|
+
变体 A1-b:步骤 3 连续快速发 3 条消息(同一轮询周期内合并)→ 徽标 = N + 3,`accountUnreadDelta: 3`。
|
|
203
|
+
|
|
204
|
+
变体 A1-c:步骤 3 前先点开另一个会话保持选中,再让 C 来消息 → 与主流程一致(C 不是当前会话,正常计数)。
|
|
205
|
+
|
|
206
|
+
变体 A1-d:先点开 C(此时 C 已加载到本地,不走 getSession 路径)→ 走 `onNewFriendMessage` 分支,与本次改动无关,用作对照:徽标不变(自动已读)或 +1(`shouldMarkCurrentSessionRead` 返回 false 时)。
|
|
207
|
+
|
|
208
|
+
### 5.3 A1 回归:分配来源不受影响
|
|
209
|
+
|
|
210
|
+
| 步骤 | 预期 |
|
|
211
|
+
|---|---|
|
|
212
|
+
| 1. 后台把一个有 k 条未读的好友从其他客服分配到当前客服的账号 X | 收到 `CmdFriendInfoChanged changeType=4` |
|
|
213
|
+
| 2. 观察账号 X 徽标 | 先 +k(`source: "onAddSession"`,注意不是 `onAddSession:getSession`),随后被 A4 的服务端刷新覆盖为服务端值(正常情况下两者相等,界面无跳动) |
|
|
214
|
+
| 3. 点开该会话 | 徽标 -k,归 0 |
|
|
215
|
+
|
|
216
|
+
### 5.4 A2:分配会话不再重复累加
|
|
217
|
+
|
|
218
|
+
| 步骤 | 预期 |
|
|
219
|
+
|---|---|
|
|
220
|
+
| 1. 账号 X 徽标为 0 | — |
|
|
221
|
+
| 2. 后台分配 1 个有 3 条未读的好友到账号 X | 徽标 = **3**(修复前是 6) |
|
|
222
|
+
| 3. 查日志 | `source: "onAddSession"` 只有 1 条,`delta.num: 3`;紧接着一条 `source: "refresh"`,`before.num: 3, after.num: 3` |
|
|
223
|
+
| 4. 点开该会话 | 徽标 = 0 |
|
|
224
|
+
| 5. 同样步骤对群聊分配(`CmdChatroomInfoChanged changeType=4`)重复一遍 | 结果相同 |
|
|
225
|
+
|
|
226
|
+
### 5.5 A4:本地未加载的会话被删除 / 转移
|
|
227
|
+
|
|
228
|
+
| 步骤 | 预期 |
|
|
229
|
+
|---|---|
|
|
230
|
+
| 1. 让账号 X 的会话 C 有 3 条未读,且排在本地未加载的页(同 5.2 步骤 1) | — |
|
|
231
|
+
| 2. 登录,只加载第 1 页,记录徽标 N | — |
|
|
232
|
+
| 3. 后台把 C 对应的好友**转移**给其他客服 | 收到 `CmdFriendInfoChanged changeType=4`,`friends[].changeType=3` |
|
|
233
|
+
| 4. 观察徽标 | = **N - 3**(修复前保持 N);日志有 `source: "refresh"`,`before.num: N, after.num: N-3` |
|
|
234
|
+
| 5. 把账号 X 其余会话点开 | 归 0 |
|
|
235
|
+
| 6. 换成后台**删除**好友(`changeType=3`)重复 1~5 | 结果相同 |
|
|
236
|
+
| 7. 换成群聊转移 / 删除(`CmdChatroomInfoChanged changeType=4 / 3`)重复 1~5 | 结果相同 |
|
|
237
|
+
|
|
238
|
+
变体 A4-b:C 已加载到本地时执行同样操作 → 走 `onRemoveSession` 本地扣减,随后 `refresh` 覆盖,两者值应一致。
|
|
239
|
+
|
|
240
|
+
### 5.6 B1:断线重连后校准
|
|
241
|
+
|
|
242
|
+
| 步骤 | 预期 |
|
|
243
|
+
|---|---|
|
|
244
|
+
| 1. 登录,账号 X 徽标为 N,本地会话和账号配平 | — |
|
|
245
|
+
| 2. 断开网络(或 devtools 里 Offline),等待 socket 触发 onclose | 日志 `socket:onclose` |
|
|
246
|
+
| 3. 断网期间:用手机端把账号 X 的某个有未读的会话读掉(服务端未读减少) | — |
|
|
247
|
+
| 4. 恢复网络,等待重连 | 日志 `socket:onopen` |
|
|
248
|
+
| 5. 观察徽标 | 补拉消息完成后,有一条 `source: "refreshAll"` 日志,徽标变为服务端当前值(比 N 少了步骤 3 读掉的条数) |
|
|
249
|
+
| 6. 首次登录(非重连)时查日志 | **没有** `source: "refreshAll"`(`ps.length` 为 0 时不刷) |
|
|
250
|
+
|
|
251
|
+
### 5.7 D:日志字段正确性
|
|
252
|
+
|
|
253
|
+
| 检查项 | 预期 |
|
|
254
|
+
|---|---|
|
|
255
|
+
| 收到新消息(会话已在本地) | `source: "onNewFriendMessage"` 或 `"onNewRoomMessage"`,`delta.num: 1`;免打扰会话时 `delta.muteNum: 1` |
|
|
256
|
+
| 点开会话 | `source: "onSessionReadChange"`,`delta.num` 为负 |
|
|
257
|
+
| 删除会话 | `source: "onRemoveSession"`,`delta.num` 为负 |
|
|
258
|
+
| 切换免打扰 | `source: "refresh"` |
|
|
259
|
+
| 任意一条日志 | `localSessionUnread.num` = 右侧该账号所有本地会话未读之和(手动数一下核对);`after.num` = 左侧徽标当前值 |
|
|
260
|
+
| `logEnable = false` | 没有任何 `client-chat-account:unreadMessageNum` 日志,功能正常 |
|
|
261
|
+
| 长时间运行 | 日志总量受 3MB 上限约束,不会无限增长 |
|
|
262
|
+
|
|
263
|
+
### 5.8 综合回归
|
|
264
|
+
|
|
265
|
+
| 场景 | 预期 |
|
|
266
|
+
|---|---|
|
|
267
|
+
| 正常收发消息、点开会话、免打扰、置顶、星标、删除会话 | 徽标行为与修复前一致 |
|
|
268
|
+
| "全部微号" 与具体微信号之间反复切换 | 徽标不变(此路径 A3 尚未处理,但不应比修复前更差) |
|
|
269
|
+
| 多个账号同时收消息 | 各账号徽标独立正确 |
|
|
270
|
+
| 群聊 @ 消息 | `lastAtMsgContent` 仍正常显示(A1 改动没有影响 `atMessage` 逻辑) |
|
|
271
|
+
| 企微(wework)入口 | 完全不受影响 |
|
|
272
|
+
| 跑一个工作日后刷新页面 | 刷新前后徽标一致,或差值明显小于修复前 |
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## 6. 兼容性说明
|
|
277
|
+
|
|
278
|
+
- `updateAccountUnreadMessageNum` 第三参数、`addSession` 第三参数、`onAddSession` 的 `unreadDelta` 字段、`ClientChatAccount` 的 `onUnreadMessageNumLog` 均为可选,缺省行为与原来一致
|
|
279
|
+
- workphone-client `src/` 下没有直接调用上述方法的地方,无需改动业务代码
|
|
280
|
+
- `client-chat-wework` 是独立实现,未改动
|
|
281
|
+
- 分配路径下 `onAddSession` 先本地 +N、随后 A4 服务端刷新覆盖,界面可能有一次短暂跳动,最终以服务端为准
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## 7. 未处理项(后续可选)
|
|
286
|
+
|
|
287
|
+
| 编号 | 内容 | 说明 |
|
|
288
|
+
|---|---|---|
|
|
289
|
+
| A3 | `addSession` 对已存在会话的静默覆盖(`client-chat-session.js` `isRefreshAll` 分支用 `Vue.set` 直接覆盖 `unreadMsgCount`)不同步账号 | 切号 / 分页拉回已存在会话时,本地多计或其他端已读的差额会在这里悄悄消失进账号。修法:覆盖前后比较 `unreadMsgCount`,差值通过 `onUpdateSession` 的 `changeProps` 流出并调整账号 |
|
|
290
|
+
| B2 | 新消息后按账号 debounce(1~2s)调 `refreshAccountUnreadMessageNum` | 兜底对账,能自动纠正所有本地增量无法覆盖的偏差(其他端已读、服务端不计某些消息类型、免打扰状态在其他端修改等) |
|
|
291
|
+
| C1 | 免打扰归属:增量按本地 `session.mute` 分桶,其他端改的 mute 本地感知不到 | 有 B2 后自愈 |
|
|
292
|
+
| C2 | `Math.max(0, …)` 钳位掩盖少算 | 可在开发环境结果 < 0 时打 warn |
|
|
293
|
+
| C3 | `updateAccountUnreadMessageNum` 是异步的(`getAccount().then`),账号不在 `accountMap` 时先 `loadData`,可能与 refresh 交叉 | `accountMap` 里已有时可改为同步执行 |
|
|
294
|
+
| C4 | 服务端计数规则核对:`msgType 10000`("你已添加了xx")、`49`(群邀请)等客户端计未读,服务端是否也计 | 需和后端确认,不一致在 `shouldIgnoreSessionByMessage` 补规则 |
|
|
295
|
+
| C5 | `getSession` 路径命中当前会话时只本地置 0,未调 `setSessionRead` 通知服务端 | 方向是"服务端 > 本地",不是本次现象,但也不一致 |
|
|
296
|
+
| — | 协议层面:`CmdNewMessage` 由服务端带上会话 `unreadMsgCount` 和账号 `unread`,客户端直接覆盖;增加"其他端已读"推送 | 长期方案,两边天然一致 |
|
|
@@ -45,10 +45,10 @@ export default class Socket {
|
|
|
45
45
|
constructor (options) {
|
|
46
46
|
options = Object.assign({
|
|
47
47
|
url: null,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
client: null,
|
|
49
|
+
logEnable: false,
|
|
50
|
+
logName: 'socket',
|
|
51
|
+
logMaxSize: 3 * 1024 * 1024, // 非网页版本最多记3M日志
|
|
52
52
|
socketAdapter: null, // 支持从外面传一个socket构造函数,但是要实现socket标准的使用方式
|
|
53
53
|
onExceedMaxReconnectLimit: null, // 超过最大重连次数回调
|
|
54
54
|
onBeforeSendMessage: null,
|
|
@@ -74,7 +74,7 @@ export default class Socket {
|
|
|
74
74
|
this.url = options.url
|
|
75
75
|
this.event = new Event()
|
|
76
76
|
this.log = new Log({
|
|
77
|
-
maxSize: options.logMaxSize, //
|
|
77
|
+
maxSize: options.logMaxSize, // 非网页版本日志大小限制
|
|
78
78
|
name: options.logName || 'socket'
|
|
79
79
|
})
|
|
80
80
|
// 会话失效
|
|
@@ -790,6 +790,10 @@ export default class Socket {
|
|
|
790
790
|
exportLogData () {
|
|
791
791
|
return this.log.exportLogData()
|
|
792
792
|
}
|
|
793
|
+
|
|
794
|
+
checkAndSync () {
|
|
795
|
+
return this.log.checkAndSync()
|
|
796
|
+
}
|
|
793
797
|
|
|
794
798
|
clearLogData () {
|
|
795
799
|
return this.log.clearLogData()
|