@aochuang/client-sdk 1.0.377-wework → 1.0.378-wework

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.
@@ -29,9 +29,10 @@ export default {
29
29
  type: {type: String, default: 'default'},
30
30
  formatter: {type: Function},
31
31
  getQuoteMessage: {type: Function},
32
+ fetchQuoteUserMethod: {type: Function},
32
33
  setChatBoxFootVnode: {type: Function}
33
34
  },
34
- data () { return {loading: false, quoteMessageData: null, errorMsg: null} },
35
+ data () { return {loading: false, quoteMessageData: null, quoteUserData: null, errorMsg: null} },
35
36
  computed: {
36
37
  contentObject () {
37
38
  return parseQuoteContent(this.content)
@@ -45,7 +46,13 @@ export default {
45
46
  quoteText () { return this.quoteInfo.text || '引用消息' },
46
47
  quoteAuthor () {
47
48
  const message = this.quoteMessageData || {}
48
- return this.quoteInfo.sendName || message.userName || message.contactName || message.roomName || this.quoteInfo.sendId || '引用消息'
49
+ if (this.quoteUserData && this.quoteUserData.name) {
50
+ return this.quoteUserData.name
51
+ }
52
+ if (!this.fetchQuoteUserMethod) {
53
+ return this.quoteInfo.sendName || message.userName || message.contactName || message.roomName || this.quoteInfo.sendId || '引用消息'
54
+ }
55
+ return this.quoteInfo.sendId || message.sendId || message.createBy || '引用消息'
49
56
  },
50
57
  quoteControl () {
51
58
  return chatControls[this.quoteMessageData && this.quoteMessageData.msgType] || TextDefault
@@ -87,12 +94,38 @@ export default {
87
94
  content: this.quoteInfo
88
95
  }).then(data => {
89
96
  this.quoteMessageData = data && data.data ? data.data : data
90
- if (!this.quoteMessageData) this.errorMsg = '未找到引用消息内容,请在手机中确认'
91
- if (this.setChatBoxFootVnode) this.setChatBoxFootVnode(this.quoteFootComponent)
97
+ if (!this.quoteMessageData) {
98
+ this.errorMsg = '未找到引用消息内容,请在手机中确认'
99
+ return
100
+ }
101
+ return this.fetchQuoteUserData()
92
102
  }).catch(() => {
93
103
  this.errorMsg = '未找到引用消息内容,请在手机中确认'
94
- if (this.setChatBoxFootVnode) this.setChatBoxFootVnode(this.quoteFootComponent)
95
- }).finally(() => { this.loading = false })
104
+ }).finally(() => {
105
+ this.loading = false
106
+ this.refreshQuoteFoot()
107
+ })
108
+ },
109
+ methods: {
110
+ refreshQuoteFoot () {
111
+ if (this.setChatBoxFootVnode) {
112
+ this.setChatBoxFootVnode(this.quoteFootComponent)
113
+ }
114
+ },
115
+ fetchQuoteUserData () {
116
+ if (!this.fetchQuoteUserMethod || !this.quoteMessageData) {
117
+ return Promise.resolve()
118
+ }
119
+ return Promise.resolve(this.fetchQuoteUserMethod({
120
+ data: this.quoteMessageData
121
+ })).then(data => {
122
+ this.quoteUserData = data || null
123
+ }).catch(() => {
124
+ this.quoteUserData = null
125
+ }).finally(() => {
126
+ this.refreshQuoteFoot()
127
+ })
128
+ }
96
129
  }
97
130
  }
98
131
  </script>
@@ -23,6 +23,7 @@ export default {
23
23
  type: {type: String, default: 'default'},
24
24
  formatter: {type: Function},
25
25
  getQuoteMessage: {type: Function},
26
+ fetchQuoteUserMethod: {type: Function},
26
27
  setChatBoxFootVnode: {type: Function}
27
28
  },
28
29
  computed: {
@@ -30,7 +31,10 @@ export default {
30
31
  defaultComponent () { return TextDefault },
31
32
  quoteComponent () { return TextQuote },
32
33
  componentProps () {
33
- return Object.assign({}, this.$attrs, this.$props, {getQuoteMessage: this.getQuoteMessage})
34
+ return Object.assign({}, this.$attrs, this.$props, {
35
+ getQuoteMessage: this.getQuoteMessage,
36
+ fetchQuoteUserMethod: this.fetchQuoteUserMethod
37
+ })
34
38
  }
35
39
  }
36
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aochuang/client-sdk",
3
- "version": "1.0.377-wework",
3
+ "version": "1.0.378-wework",
4
4
  "description": "",
5
5
  "files": [
6
6
  "common",
@@ -146,6 +146,21 @@ export default class ClientChatMessage {
146
146
  }
147
147
  }
148
148
  if (fireEvent !== false) {
149
+ // 先执行onAddMessageSuccess再发add-message事件,保证会话的getSession轮询先由这里发起、更新会话的回调排在最前面,
150
+ // 外部监听add-message后再调getSession只是复用同一个轮询
151
+ // try/catch是为了避免回调里的异常把add-message事件吞掉(外部的新消息提醒、本地消息缓存都依赖这个事件)
152
+ try {
153
+ this.onAddMessageSuccess && this.onAddMessageSuccess({
154
+ data,
155
+ lastMessageTime,
156
+ isBeforeLastMessage
157
+ })
158
+ } catch (error) {
159
+ console.error('[client-chat-message] onAddMessageSuccess error', {
160
+ messageId: data.id,
161
+ error
162
+ })
163
+ }
149
164
  // 如果消息包含这种情况,就不能往外发送add-message事件
150
165
  // 因为例如群发的消息,他没有会话,导致前端在处理来了新消息通知铃声提醒,获取会话一直获取不到,然后会总是发送请求
151
166
  if (!isBeforeLastMessage && !isAutoReadMessage(data) && !shouldIgnoreSessionByMessage(data) && !isDeletedMsg(data) && !isBlockedMsg(data)) {
@@ -153,11 +168,6 @@ export default class ClientChatMessage {
153
168
  data
154
169
  })
155
170
  }
156
- this.onAddMessageSuccess && this.onAddMessageSuccess({
157
- data,
158
- lastMessageTime,
159
- isBeforeLastMessage
160
- })
161
171
  }
162
172
  }
163
173
 
@@ -242,37 +242,19 @@ export default class ClientChatSession {
242
242
  }
243
243
  }
244
244
 
245
- _addGetSessionSerializeTask (pollRequest, serializeMethod, taskOptions = {}) {
246
- if (!serializeMethod) {
247
- return false
248
- }
249
- const messageId = taskOptions.messageId
250
- if (messageId && pollRequest.serializeTaskMap[messageId]) {
251
- return false
252
- }
253
- const task = {
254
- messageId,
255
- wechatTime: taskOptions.wechatTime || 0,
256
- index: pollRequest.serializeTasks.length,
257
- serializeMethod
258
- }
259
- pollRequest.serializeTasks.push(task)
260
- if (messageId) {
261
- pollRequest.serializeTaskMap[messageId] = task
262
- }
263
- return true
264
- }
265
-
266
- getSession (sessionId, serializeMethod, taskOptions = {}) {
245
+ getSession (sessionId, serializeMethod) {
267
246
  if (this.sessionMap[sessionId]) {
268
247
  return Promise.resolve({
269
248
  data: this.sessionMap[sessionId]
270
249
  })
271
250
  }
272
251
  // 这里需要轮询从后端获取会话,后端会话更新和创建是异步的,所以要多轮训请求几次
252
+ // 同一个会话只会有一个轮询,轮询期间再次调用只把serializeMethod挂到这个轮询上,等结果回来后依次执行
273
253
  let pollRequest = this.pollRequestMap[sessionId]
274
254
  if (pollRequest && pollRequest.ps) {
275
- this._addGetSessionSerializeTask(pollRequest, serializeMethod, taskOptions)
255
+ if (serializeMethod) {
256
+ pollRequest.serializeMethods.push(serializeMethod)
257
+ }
276
258
  return pollRequest.ps
277
259
  }
278
260
 
@@ -292,50 +274,33 @@ export default class ClientChatSession {
292
274
  return Promise.reject(error)
293
275
  })
294
276
  })
295
- pollRequest.serializeTasks = []
296
- pollRequest.serializeTaskMap = {}
277
+ pollRequest.serializeMethods = serializeMethod ? [serializeMethod] : []
297
278
  pollRequest.requestCount = 0
298
279
  pollRequest.emptyResponseCount = 0
299
280
  pollRequest.requestErrorCount = 0
300
281
  pollRequest.lastRequestError = null
301
282
  pollRequest.startedAt = Date.now()
302
- this._addGetSessionSerializeTask(pollRequest, serializeMethod, taskOptions)
303
283
  this.pollRequestMap[sessionId] = pollRequest
304
284
  this._addGetSessionLog('创建会话轮询', {
305
- sessionId,
306
- messageId: taskOptions.messageId,
307
- wechatTime: taskOptions.wechatTime,
308
- taskCount: pollRequest.serializeTasks.length
285
+ sessionId
309
286
  })
310
287
  pollRequest.ps = pollRequest.start().then(rs => {
311
288
  if (!rs.data) {
312
289
  return Promise.reject('未找到会话' + sessionId)
313
290
  }
314
291
  /**
315
- * 轮询合并上下文,会依次传给每个 serializeMethod(见 client-chat.js onCmdNewMessage 里 getSession 的回调)
292
+ * 轮询合并上下文,会依次传给每个 serializeMethod(见 client-chat.js onAddMessageSuccess 里 getSession 的回调)
316
293
  * baseLastMsgTime 服务端返回的会话 lastMsgTime,用来判断某条消息服务端是否已经算进 unreadMsgCount
317
- * processedMessageIds 本次轮询期间处理过的所有消息 id
318
- * skippedMessageIds 服务端返回的会话已经包含(wechatTime <= baseLastMsgTime)、本地不再给会话未读 +1 的消息 id
319
- * unreadMessageIds 本地给会话未读 +1 的消息 id
320
294
  * accountUnreadDelta 本次轮询期间需要累加到工作微信号(账号)未读数量上的条数。
321
- * 注意它和 unreadMessageIds.length 不同:账号未读初始值是登录时取的,不包含本次收到的任何消息,
322
- * 所以被 skip 的消息也要算进来;只有"正在看当前会话被直接标记已读"的消息不算
295
+ * 账号未读初始值是登录时取的,不包含本次收到的任何消息,所以服务端已经算进会话 unreadMsgCount 的消息也要算进来;
296
+ * 只有"正在看当前会话被直接标记已读"的消息不算
323
297
  */
324
298
  const context = {
325
299
  baseLastMsgTime: rs.data.lastMsgTime || 0,
326
- processedMessageIds: [],
327
- skippedMessageIds: [],
328
- unreadMessageIds: [],
329
300
  accountUnreadDelta: 0
330
301
  }
331
- const serializeTasks = pollRequest.serializeTasks.slice().sort((a, b) => {
332
- return a.wechatTime - b.wechatTime || a.index - b.index
333
- })
334
- serializeTasks.forEach(task => {
335
- rs = task.serializeMethod(rs, context) || rs
336
- if (task.messageId) {
337
- context.processedMessageIds.push(task.messageId)
338
- }
302
+ pollRequest.serializeMethods.forEach(method => {
303
+ rs = method(rs, context) || rs
339
304
  })
340
305
  // wechatAccountId 传 null 表示非分页来源,onAddSession 会把未读同步到账号;
341
306
  // 同时带上 unreadDelta,让账号只累加本次新增的条数,而不是服务端返回的整个 unreadMsgCount(那里面的存量部分账号初始值已经包含了)
@@ -353,9 +318,7 @@ export default class ClientChatSession {
353
318
  lastMsgTime: rs.data.lastMsgTime,
354
319
  lastMsgId: rs.data.lastMsgId,
355
320
  unreadMsgCount: rs.data.unreadMsgCount,
356
- processedMessageCount: context.processedMessageIds.length,
357
- skippedMessageCount: context.skippedMessageIds.length,
358
- unreadMessageCount: context.unreadMessageIds.length,
321
+ mergedCount: pollRequest.serializeMethods.length,
359
322
  accountUnreadDelta: context.accountUnreadDelta,
360
323
  hasSessionMap: !!this.sessionMap[sessionId],
361
324
  hasAllSessionGroup: !!this._getSessionBySessionGroup(sessionId, ALL_WECHAT_ACCOUNT_ID),
@@ -437,22 +437,6 @@ class ClientChat {
437
437
  }
438
438
  const localSession = this.session.findSession(({ session }) => session.conversationId === sessionId)
439
439
  if (!localSession) {
440
- if (!this.session.pollRequestMap[sessionId]) {
441
- this.socket.addLog({
442
- group: 'client-chat-message:onAddMessageSuccess',
443
- content: {
444
- title: '未获取到会话,开始从服务端获取',
445
- data: {
446
- sessionId,
447
- accountId,
448
- wechatFriendId: data.wechatFriendId,
449
- wechatAccountId: data.wechatAccountId,
450
- messageId: data.id,
451
- wechatTime: data.wechatTime
452
- }
453
- }
454
- })
455
- }
456
440
  return this.session.getSession(sessionId, (rs, context) => {
457
441
  if (rs && rs.data) {
458
442
  const isAfterServerMessage = data.wechatTime > context.baseLastMsgTime
@@ -467,19 +451,16 @@ class ClientChat {
467
451
  // 正在看这个会话并且允许自动标记已读
468
452
  const isCurrentSessionRead = this.sessionManage.currentSession && this.sessionManage.currentSession.conversationId === sessionId && this.shouldMarkCurrentSessionRead(sessionId, data)
469
453
  // 会话未读数量:isAfterServerMessage 为 true 表示这条消息比服务端返回的会话 lastMsgTime 新,
470
- // 服务端返回的 unreadMsgCount 还没算它,需要本地 +1;否则服务端已经算进去了,skip 掉避免重复
454
+ // 服务端返回的 unreadMsgCount 还没算它,需要本地 +1;否则服务端已经算进去了,不再重复 +1
471
455
  if (!data.isSend && isAfterServerMessage) {
472
456
  if (isCurrentSessionRead) {
473
457
  rs.data.unreadMsgCount = 0
474
458
  } else {
475
459
  rs.data.unreadMsgCount = (rs.data.unreadMsgCount || 0) + 1
476
- context.unreadMessageIds.push(data.id)
477
460
  }
478
- } else {
479
- context.skippedMessageIds.push(data.id)
480
461
  }
481
462
  // 账号未读数量:和会话未读数量的判断口径不一样。
482
- // 账号未读初始值是登录时从服务端取的,不包含这条新消息,所以不管这条消息有没有被服务端算进会话的 unreadMsgCount(即不管是否被 skip),
463
+ // 账号未读初始值是登录时从服务端取的,不包含这条新消息,所以不管这条消息有没有被服务端算进会话的 unreadMsgCount,
483
464
  // 账号都要 +1。唯一不加的情况是"正在看当前会话并被直接标记已读"(此时会话未读被置 0,不会再通过 onSessionReadChange 扣减账号)。
484
465
  // 这个累计值会通过 addSession(rs.data, null, { unreadDelta }) 传给 onAddSession,账号只累加这个增量而不是整个 unreadMsgCount
485
466
  if (!data.isSend && !(isAfterServerMessage && isCurrentSessionRead)) {
@@ -487,9 +468,6 @@ class ClientChat {
487
468
  }
488
469
  }
489
470
  return rs
490
- }, {
491
- messageId: data.id,
492
- wechatTime: data.wechatTime
493
471
  }).catch(() => {})
494
472
  } else {
495
473
  this.session.updateSession(sessionId, ({ session }) => {
@@ -584,22 +562,6 @@ class ClientChat {
584
562
  // 更新会话未读消息数量
585
563
  const localSession = this.session.findSession(({ session }) => session.conversationId === sessionId)
586
564
  if (!localSession) {
587
- if (!this.session.pollRequestMap[sessionId]) {
588
- this.socket.addLog({
589
- group: 'client-chat-message:onAddMessageSuccess',
590
- content: {
591
- title: '未获取到会话,开始从服务端获取',
592
- data: {
593
- sessionId,
594
- accountId,
595
- wechatChatroomId: data.wechatChatroomId,
596
- wechatAccountId: data.wechatAccountId,
597
- messageId: data.id,
598
- wechatTime: data.wechatTime
599
- }
600
- }
601
- })
602
- }
603
565
  return this.session.getSession(sessionId, (rs, context) => {
604
566
  if (rs && rs.data) {
605
567
  const isAfterServerMessage = data.wechatTime > context.baseLastMsgTime
@@ -614,22 +576,19 @@ class ClientChat {
614
576
  // 正在看这个会话并且允许自动标记已读
615
577
  const isCurrentSessionRead = this.sessionManage.currentSession && this.sessionManage.currentSession.conversationId === sessionId && this.shouldMarkCurrentSessionRead(sessionId, data)
616
578
  // 会话未读数量:isAfterServerMessage 为 true 表示这条消息比服务端返回的会话 lastMsgTime 新,
617
- // 服务端返回的 unreadMsgCount 还没算它,需要本地 +1;否则服务端已经算进去了,skip 掉避免重复
579
+ // 服务端返回的 unreadMsgCount 还没算它,需要本地 +1;否则服务端已经算进去了,不再重复 +1
618
580
  if (!data.isSend && isAfterServerMessage) {
619
581
  if (isCurrentSessionRead) {
620
582
  rs.data.unreadMsgCount = 0
621
583
  } else {
622
584
  rs.data.unreadMsgCount = (rs.data.unreadMsgCount || 0) + 1
623
- context.unreadMessageIds.push(data.id)
624
585
  if (atMessage) {
625
586
  rs.data.lastAtMsgContent = appendLastAtMsgContent(rs.data.lastAtMsgContent, atMessage)
626
587
  }
627
588
  }
628
- } else {
629
- context.skippedMessageIds.push(data.id)
630
589
  }
631
590
  // 账号未读数量:和会话未读数量的判断口径不一样。
632
- // 账号未读初始值是登录时从服务端取的,不包含这条新消息,所以不管这条消息有没有被服务端算进会话的 unreadMsgCount(即不管是否被 skip),
591
+ // 账号未读初始值是登录时从服务端取的,不包含这条新消息,所以不管这条消息有没有被服务端算进会话的 unreadMsgCount,
633
592
  // 账号都要 +1。唯一不加的情况是"正在看当前会话并被直接标记已读"(此时会话未读被置 0,不会再通过 onSessionReadChange 扣减账号)。
634
593
  // 这个累计值会通过 addSession(rs.data, null, { unreadDelta }) 传给 onAddSession,账号只累加这个增量而不是整个 unreadMsgCount
635
594
  if (!data.isSend && !(isAfterServerMessage && isCurrentSessionRead)) {
@@ -637,9 +596,6 @@ class ClientChat {
637
596
  }
638
597
  }
639
598
  return rs
640
- }, {
641
- messageId: data.id,
642
- wechatTime: data.wechatTime
643
599
  }).catch(() => {})
644
600
  } else {
645
601
  this.session.updateSession(sessionId, ({ session }) => {
@@ -84,13 +84,15 @@ SDK 里维护着两套彼此独立的本地"账本":
84
84
  ```js
85
85
  // 会话未读:只在服务端没算过这条消息时 +1(原逻辑不变)
86
86
  if (!data.isSend && isAfterServerMessage) { ... }
87
- // 账号未读:不管是否被 skip 都 +1,只有"正在看当前会话被直接标记已读"不加
87
+ // 账号未读:不管服务端是否已经算进会话 unreadMsgCount 都 +1,只有"正在看当前会话被直接标记已读"不加
88
88
  if (!data.isSend && !(isAfterServerMessage && isCurrentSessionRead)) {
89
89
  context.accountUnreadDelta += 1
90
90
  }
91
91
  ```
92
92
 
93
- 注意 `accountUnreadDelta` **不等于** `unreadMessageIds.length`:被 skip 的消息表示服务端返回的会话已经把它算进 `unreadMsgCount`,但账号初始值是登录时取的,仍然不含这条,所以账号还是要 +1。
93
+ 注意 `accountUnreadDelta` **不等于** 本次给会话 `unreadMsgCount` +1 的条数:`isAfterServerMessage` 为 false 的消息表示服务端返回的会话已经把它算进 `unreadMsgCount`,但账号初始值是登录时取的,仍然不含这条,所以账号还是要 +1。
94
+
95
+ `getSession(sessionId, serializeMethod)` 只按 `sessionId` 聚合:同一个会话轮询期间的所有回调按调用顺序依次执行,不再依赖消息 id / 时间做去重或排序(消息层 `addMessage` 已按 id 去重)。
94
96
 
95
97
  - `onAddSession`(第 132 行附近):
96
98
 
@@ -21,8 +21,9 @@ export default class ClientChatMessage {
21
21
  */
22
22
  messageData: {}
23
23
  })
24
-
24
+
25
25
  messageMap = {}
26
+ lastMessageTimeMap = {}
26
27
  tempMessageMap = {}
27
28
  checkMessageSendResultTaskList = []
28
29
 
@@ -100,6 +101,8 @@ export default class ClientChatMessage {
100
101
  delete this.tempMessageMap[data.id]
101
102
  }
102
103
  const groupField = data[this.groupField]
104
+ const lastMessageTime = this.getLastMessageTime(groupField)
105
+ const isBeforeLastMessage = !data.isSend && lastMessageTime && data[this.sortField] < lastMessageTime
103
106
  if (!this.data.messageData[groupField]) {
104
107
  Vue.set(this.data.messageData, groupField, {})
105
108
  }
@@ -115,14 +118,27 @@ export default class ClientChatMessage {
115
118
  }
116
119
  this.data.messageData[groupField][sortFields.day][sortFields.milliseconds].push(data)
117
120
  this.messageMap[data.id] = data
121
+ this.setLastMessageTime(groupField, data[this.sortField], data)
118
122
  if (data.isSend && data.status === 1 && !data._temp) this.addCheckMessageSendResultTask(data)
119
123
  if (fireEvent !== false) {
124
+ try {
125
+ this.onAddMessageSuccess && this.onAddMessageSuccess({
126
+ data,
127
+ lastMessageTime,
128
+ isBeforeLastMessage
129
+ })
130
+ } catch (error) {
131
+ console.error('[client-chat-message] onAddMessageSuccess error', {
132
+ messageId: data.id,
133
+ error
134
+ })
135
+ }
136
+ if (isBeforeLastMessage) {
137
+ return
138
+ }
120
139
  this.event && this.event.emit('add-message', {
121
140
  data
122
141
  })
123
- this.onAddMessageSuccess && this.onAddMessageSuccess({
124
- data
125
- })
126
142
  }
127
143
  }
128
144
 
@@ -159,7 +175,7 @@ export default class ClientChatMessage {
159
175
  delete this.data.messageData[groupField]
160
176
  }
161
177
  this.event && this.event.emit('remove-message', {
162
- data
178
+ data: message
163
179
  })
164
180
  }
165
181
 
@@ -172,9 +188,44 @@ export default class ClientChatMessage {
172
188
  if (!props) {
173
189
  return
174
190
  }
191
+ const groupField = message[this.groupField]
192
+ const oldSortFieldValue = message[this.sortField]
193
+ const oldSortFields = this.getSortField(oldSortFieldValue)
175
194
  Object.keys(props).forEach(key => {
176
- message[key] = props[key]
195
+ Vue.set(message, key, props[key])
177
196
  })
197
+ if (typeof props[this.sortField] !== 'undefined' && props[this.sortField] !== oldSortFieldValue) {
198
+ const oldBucket = this.data.messageData[groupField] &&
199
+ this.data.messageData[groupField][oldSortFields.day] &&
200
+ this.data.messageData[groupField][oldSortFields.day][oldSortFields.milliseconds]
201
+ if (oldBucket) {
202
+ const index = oldBucket.findIndex(item => item.id === message.id)
203
+ if (index >= 0) {
204
+ oldBucket.splice(index, 1)
205
+ }
206
+ if (!oldBucket.length) {
207
+ Vue.delete(this.data.messageData[groupField][oldSortFields.day], oldSortFields.milliseconds)
208
+ }
209
+ if (!Object.keys(this.data.messageData[groupField][oldSortFields.day]).length) {
210
+ Vue.delete(this.data.messageData[groupField], oldSortFields.day)
211
+ }
212
+ }
213
+ const newSortFields = this.getSortField(message[this.sortField])
214
+ if (!this.data.messageData[groupField]) {
215
+ Vue.set(this.data.messageData, groupField, {})
216
+ }
217
+ if (!this.data.messageData[groupField][newSortFields.day]) {
218
+ Vue.set(this.data.messageData[groupField], newSortFields.day, {})
219
+ }
220
+ if (!this.data.messageData[groupField][newSortFields.day][newSortFields.milliseconds]) {
221
+ Vue.set(this.data.messageData[groupField][newSortFields.day], newSortFields.milliseconds, [])
222
+ }
223
+ const newBucket = this.data.messageData[groupField][newSortFields.day][newSortFields.milliseconds]
224
+ if (!newBucket.some(item => item.id === message.id)) {
225
+ newBucket.push(message)
226
+ }
227
+ this.setLastMessageTime(groupField, message[this.sortField], message)
228
+ }
178
229
  }
179
230
 
180
231
  getMessage (id) {
@@ -315,6 +366,25 @@ export default class ClientChatMessage {
315
366
  this.checkMessageSendResultTaskList.forEach(task => task.cancel())
316
367
  this.checkMessageSendResultTaskList = []
317
368
  this.tempMessageMap = {}
369
+ this.messageMap = {}
370
+ this.lastMessageTimeMap = {}
318
371
  this.data.messageData = {}
319
372
  }
373
+
374
+ getLastMessageTime (groupField) {
375
+ return this.lastMessageTimeMap[groupField]
376
+ }
377
+
378
+ setLastMessageTime (groupField, messageTime, message) {
379
+ if (!groupField || !messageTime || (message && message.msgType === '_EMPTY_')) {
380
+ return
381
+ }
382
+ if (message && message._temp) {
383
+ return
384
+ }
385
+ const lastMessageTime = this.getLastMessageTime(groupField)
386
+ if (!lastMessageTime || messageTime > lastMessageTime) {
387
+ this.lastMessageTimeMap[groupField] = messageTime
388
+ }
389
+ }
320
390
  }
@@ -1,5 +1,5 @@
1
1
  import Vue from 'vue'
2
- import { isEmptyObject } from '../../../utils/util.js'
2
+ import { createPollRequest, isEmptyObject } from '../../../utils/util.js'
3
3
 
4
4
  const loopLoadAssignSessionData = (fetchFn, params) => {
5
5
  let lastPs = null
@@ -87,6 +87,8 @@ export default class ClientChatSession {
87
87
  })
88
88
 
89
89
  accountIds = []
90
+
91
+ pollRequestMap = {}
90
92
 
91
93
  sessionMap = {}
92
94
 
@@ -146,6 +148,7 @@ export default class ClientChatSession {
146
148
  groupField: null,
147
149
  sortField: null,
148
150
  onBeforeAddSession: null,
151
+ onAddSession: null,
149
152
  loadSessionDataMethod: null,
150
153
  loadAssignTaskSessionDataMethod: null,
151
154
  stickyTopSessionMethod: null,
@@ -170,6 +173,7 @@ export default class ClientChatSession {
170
173
  throw new Error('缺少getSessionMethod配置')
171
174
  }
172
175
  this.onBeforeAddSession = options.onBeforeAddSession
176
+ this.onAddSession = options.onAddSession
173
177
  this.loadSessionData = options.loadSessionDataMethod
174
178
  this.updateSessionRead = options.updateSessionReadMethod
175
179
  this.getSessionMethod = options.getSessionMethod
@@ -187,6 +191,8 @@ export default class ClientChatSession {
187
191
  this.sessionMap = {}
188
192
  this.data.sessionData = {}
189
193
  this.data.sessionGroupData = {}
194
+ this._lastUpdateSessionMap = {}
195
+ this._reverseLastUpdateSessionMap = {}
190
196
  // this.data.sessionUnreadCountMap = {}
191
197
  this.data.sessionMuteMap = {}
192
198
  }
@@ -202,22 +208,62 @@ export default class ClientChatSession {
202
208
  this.checkAndUpdateLastUpdateSession()
203
209
  }
204
210
 
205
- getSession (sessionId) {
211
+ getSession (sessionId, serializeMethod) {
206
212
  if (this.sessionMap[sessionId]) {
207
213
  return Promise.resolve({
208
214
  data: this.sessionMap[sessionId]
209
215
  })
210
216
  }
211
- return this.getSessionMethod({
212
- id: sessionId
213
- }).then(rs => {
214
- if (rs.data) {
215
- this.addSession(rs.data)
216
- return rs
217
- } else {
217
+ let pollRequest = this.pollRequestMap[sessionId]
218
+ if (pollRequest && pollRequest.promise) {
219
+ if (serializeMethod) {
220
+ pollRequest.serializeMethods.push(serializeMethod)
221
+ }
222
+ return pollRequest.promise
223
+ }
224
+ pollRequest = createPollRequest(({ done }) => {
225
+ return this.getSessionMethod({
226
+ id: sessionId
227
+ }).then(rs => {
228
+ if (rs && rs.data) {
229
+ done(Object.assign({}, rs, {
230
+ data: Object.assign({}, rs.data, {
231
+ id: sessionId
232
+ })
233
+ }))
234
+ }
235
+ })
236
+ })
237
+ pollRequest.serializeMethods = serializeMethod ? [serializeMethod] : []
238
+ this.pollRequestMap[sessionId] = pollRequest
239
+ pollRequest.promise = pollRequest.start().then(rs => {
240
+ if (!rs || !rs.data) {
218
241
  return Promise.reject('未找到会话' + sessionId)
219
242
  }
243
+ const context = {
244
+ baseLastMsgTime: rs.data.lastMsgTime || 0,
245
+ accountUnreadDelta: 0
246
+ }
247
+ pollRequest.serializeMethods.forEach(method => {
248
+ rs = method(rs, context) || rs
249
+ })
250
+ this.addSession(rs.data, {
251
+ unreadDelta: context.accountUnreadDelta
252
+ })
253
+ return rs
254
+ }).finally(() => {
255
+ if (this.pollRequestMap[sessionId] === pollRequest) {
256
+ delete this.pollRequestMap[sessionId]
257
+ }
258
+ })
259
+ return pollRequest.promise
260
+ }
261
+
262
+ stopGetSessionPollRequests () {
263
+ Object.keys(this.pollRequestMap).forEach(sessionId => {
264
+ this.pollRequestMap[sessionId].stop()
220
265
  })
266
+ this.pollRequestMap = {}
221
267
  }
222
268
 
223
269
  getSessionByLocal (sessionId) {
@@ -275,7 +321,98 @@ export default class ClientChatSession {
275
321
  milliseconds: Math.abs(milliseconds - 86400000) // 排序,由大到小
276
322
  }
277
323
  }
278
-
324
+
325
+ _removeSessionFromBuckets (buckets, sessionId) {
326
+ if (!buckets) {
327
+ return
328
+ }
329
+ Object.keys(buckets).forEach(topField => {
330
+ const dayBuckets = buckets[topField]
331
+ Object.keys(dayBuckets || {}).forEach(day => {
332
+ const timeBuckets = dayBuckets[day]
333
+ Object.keys(timeBuckets || {}).forEach(milliseconds => {
334
+ const items = timeBuckets[milliseconds]
335
+ if (!Array.isArray(items)) {
336
+ return
337
+ }
338
+ for (let index = items.length - 1; index >= 0; index -= 1) {
339
+ if (items[index] && items[index].id === sessionId) {
340
+ items.splice(index, 1)
341
+ }
342
+ }
343
+ if (!items.length) {
344
+ Vue.delete(timeBuckets, milliseconds)
345
+ }
346
+ })
347
+ if (isEmptyObject(timeBuckets)) {
348
+ Vue.delete(dayBuckets, day)
349
+ }
350
+ })
351
+ if (isEmptyObject(dayBuckets)) {
352
+ Vue.delete(buckets, topField)
353
+ }
354
+ })
355
+ }
356
+
357
+ _removeSessionFromDisplayData (sessionId) {
358
+ this._removeSessionFromBuckets(this.data.sessionData, sessionId)
359
+ Object.keys(this.data.sessionGroupData).forEach(groupField => {
360
+ this._removeSessionFromBuckets(this.data.sessionGroupData[groupField], sessionId)
361
+ if (isEmptyObject(this.data.sessionGroupData[groupField])) {
362
+ Vue.delete(this.data.sessionGroupData, groupField)
363
+ }
364
+ })
365
+ }
366
+
367
+ _removeSessionFromTimeMap (timeMap, sessionId) {
368
+ Object.keys(timeMap || {}).forEach(day => {
369
+ Object.keys(timeMap[day] || {}).forEach(milliseconds => {
370
+ const items = timeMap[day][milliseconds]
371
+ if (!Array.isArray(items)) {
372
+ return
373
+ }
374
+ for (let index = items.length - 1; index >= 0; index -= 1) {
375
+ if (items[index] && items[index].id === sessionId) {
376
+ items.splice(index, 1)
377
+ }
378
+ }
379
+ if (!items.length) {
380
+ delete timeMap[day][milliseconds]
381
+ }
382
+ })
383
+ if (isEmptyObject(timeMap[day])) {
384
+ delete timeMap[day]
385
+ }
386
+ })
387
+ }
388
+
389
+ _insertSessionIntoBuckets (buckets, session, topField, sortFields) {
390
+ if (!buckets[topField]) {
391
+ Vue.set(buckets, topField, {})
392
+ }
393
+ if (!buckets[topField][sortFields.day]) {
394
+ Vue.set(buckets[topField], sortFields.day, {})
395
+ }
396
+ if (!buckets[topField][sortFields.day][sortFields.milliseconds]) {
397
+ Vue.set(buckets[topField][sortFields.day], sortFields.milliseconds, [])
398
+ }
399
+ const items = buckets[topField][sortFields.day][sortFields.milliseconds]
400
+ if (!items.some(item => item.id === session.id)) {
401
+ items.push(session)
402
+ }
403
+ }
404
+
405
+ _insertSessionIntoDisplayData (session) {
406
+ const topField = session.stickyOnTop ? 0 : 1
407
+ const sortFields = this.getSortField(session[this.sortField])
408
+ this._insertSessionIntoBuckets(this.data.sessionData, session, topField, sortFields)
409
+ const groupField = session[this.groupField] || 'unkonw'
410
+ if (!this.data.sessionGroupData[groupField]) {
411
+ Vue.set(this.data.sessionGroupData, groupField, {})
412
+ }
413
+ this._insertSessionIntoBuckets(this.data.sessionGroupData[groupField], session, topField, sortFields)
414
+ }
415
+
279
416
  /**
280
417
  * {
281
418
  * "id": "3d5398c24f1ae633047202fe17276571ef5e537e",
@@ -292,7 +429,7 @@ export default class ClientChatSession {
292
429
  * "wechatAccountId": "2a39a725814acf07502299ab2285fff8d44377f5"
293
430
  * }
294
431
  */
295
- addSession (data) {
432
+ addSession (data, options = {}) {
296
433
  if (!data || !data.id) {
297
434
  throw new Error('缺少必须参数id')
298
435
  }
@@ -301,22 +438,20 @@ export default class ClientChatSession {
301
438
  }) === false) {
302
439
  return
303
440
  }
304
- if (this.sessionMap[data.id]) {
305
- return
306
- }
307
- const topField = data.stickyOnTop ? 0 : 1 // 置顶
308
- if (!this.data.sessionData[topField]) {
309
- Vue.set(this.data.sessionData, topField, {})
310
- }
311
- // 所有的
312
- const sortFields = this.getSortField(data[this.sortField])
313
- if (!this.data.sessionData[topField][sortFields.day]) {
314
- Vue.set(this.data.sessionData[topField], sortFields.day, {})
315
- }
316
- if (!this.data.sessionData[topField][sortFields.day][sortFields.milliseconds]) {
317
- Vue.set(this.data.sessionData[topField][sortFields.day], sortFields.milliseconds, [])
441
+ const oldSession = this.sessionMap[data.id]
442
+ if (oldSession) {
443
+ if (oldSession.lastMsgTime && data.lastMsgTime && oldSession.lastMsgTime > data.lastMsgTime) {
444
+ return oldSession
445
+ }
446
+ this._removeSessionFromDisplayData(data.id)
447
+ this._removeSessionFromTimeMap(this._lastUpdateSessionMap, data.id)
448
+ this._removeSessionFromTimeMap(this._reverseLastUpdateSessionMap, data.id)
449
+ Object.keys(data).forEach(key => {
450
+ Vue.set(oldSession, key, data[key])
451
+ })
452
+ data = oldSession
318
453
  }
319
- this.data.sessionData[topField][sortFields.day][sortFields.milliseconds].push(data)
454
+ this._insertSessionIntoDisplayData(data)
320
455
  // 记录lastUpdateSession的顺序,因为后续分页加载会话数据的时候,加载的参数需要获取目前会话数据中最久远的一条会话记录,作为下载加载会话的参考数据
321
456
  const lastUpdateSortFields = this.getSortField(data.lastUpdateTime)
322
457
  if (!this._lastUpdateSessionMap) {
@@ -341,21 +476,7 @@ export default class ClientChatSession {
341
476
  this._reverseLastUpdateSessionMap[reverseLastUpdateSortFields.day][reverseLastUpdateSortFields.milliseconds] = []
342
477
  }
343
478
  this._reverseLastUpdateSessionMap[reverseLastUpdateSortFields.day][reverseLastUpdateSortFields.milliseconds].push(data)
344
- // 分组的
345
479
  const groupField = data[this.groupField] || 'unkonw'
346
- if (!this.data.sessionGroupData[groupField]) {
347
- Vue.set(this.data.sessionGroupData, groupField, {})
348
- }
349
- if (!this.data.sessionGroupData[groupField][topField]) {
350
- Vue.set(this.data.sessionGroupData[groupField], topField, {})
351
- }
352
- if (!this.data.sessionGroupData[groupField][topField][sortFields.day]) {
353
- Vue.set(this.data.sessionGroupData[groupField][topField], sortFields.day, {})
354
- }
355
- if (!this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds]) {
356
- Vue.set(this.data.sessionGroupData[groupField][topField][sortFields.day], sortFields.milliseconds, [])
357
- }
358
- this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds].push(data)
359
480
  this.sessionMap[data.id] = data
360
481
  // if (typeof this.data.sessionUnreadCountMap[groupField] !== 'number') {
361
482
  // Vue.set(this.data.sessionUnreadCountMap, groupField, 0)
@@ -382,6 +503,11 @@ export default class ClientChatSession {
382
503
  if (data.lastMsgTime && (!this.lastSession || data.lastMsgTime < this.lastSession.lastMsgTime)) {
383
504
  this.lastSession = data
384
505
  }
506
+ this.onAddSession && this.onAddSession({
507
+ session: data,
508
+ unreadDelta: options.unreadDelta
509
+ })
510
+ return data
385
511
  }
386
512
 
387
513
  removeSession (id, checkLastUpdateSession) {
@@ -392,6 +518,9 @@ export default class ClientChatSession {
392
518
  if (!session) {
393
519
  return
394
520
  }
521
+ this._removeSessionFromDisplayData(id)
522
+ this._removeSessionFromTimeMap(this._lastUpdateSessionMap, id)
523
+ this._removeSessionFromTimeMap(this._reverseLastUpdateSessionMap, id)
395
524
  const topField = session.stickyOnTop ? 0 : 1 // 置顶
396
525
  const sortFields = this.getSortField(session[this.sortField])
397
526
  if (this.data.sessionData[topField] && this.data.sessionData[topField][sortFields.day] && this.data.sessionData[topField][sortFields.day][sortFields.milliseconds]) {
@@ -489,7 +618,15 @@ export default class ClientChatSession {
489
618
  }
490
619
  // lastSession是最小的时间,就是更早的,因为加载更多是从现在的加载历史的
491
620
  const dayKeys = Object.keys(this._lastUpdateSessionMap)
621
+ if (!dayKeys.length) {
622
+ this.lastUpdateSession = null
623
+ this.lastUpdateTime = null
624
+ return
625
+ }
492
626
  const millisecondsKeys = Object.keys(this._lastUpdateSessionMap[dayKeys[dayKeys.length - 1]])
627
+ if (!millisecondsKeys.length) {
628
+ return
629
+ }
493
630
  const lastSessionSort = (this._lastUpdateSessionMap[dayKeys[dayKeys.length - 1]][millisecondsKeys[millisecondsKeys.length - 1]] || []).sort((a, b) => {
494
631
  return a.lastUpdateTime - b.lastUpdateTime
495
632
  })
@@ -509,7 +646,15 @@ export default class ClientChatSession {
509
646
  }
510
647
  // lastSession是最小的时间,就是更早的,因为加载更多是从现在的加载历史的
511
648
  const dayKeys = Object.keys(this._reverseLastUpdateSessionMap)
649
+ if (!dayKeys.length) {
650
+ this.reverseLastUpdateSession = null
651
+ this.reverseLastUpdateTime = null
652
+ return
653
+ }
512
654
  const millisecondsKeys = Object.keys(this._reverseLastUpdateSessionMap[dayKeys[dayKeys.length - 1]])
655
+ if (!millisecondsKeys.length) {
656
+ return
657
+ }
513
658
  const lastSessionSort = (this._reverseLastUpdateSessionMap[dayKeys[dayKeys.length - 1]][millisecondsKeys[millisecondsKeys.length - 1]] || []).sort((a, b) => {
514
659
  return b.lastUpdateTime - a.lastUpdateTime
515
660
  })
@@ -578,163 +723,40 @@ export default class ClientChatSession {
578
723
  } else {
579
724
  nextProps = callback
580
725
  }
581
- if (nextProps) {
582
- // 分组的
583
- const groupField = session[this.groupField] || 'unkonw'
584
- const { unreadMsgCount, stickyOnTop, mute, lastMsgTime, ...nextUpdateProps } = nextProps
585
- Object.keys(nextUpdateProps).forEach(k => {
586
- Vue.set(session, k, nextUpdateProps[k])
587
- })
588
- // 处理会话时间
589
- if (typeof lastMsgTime !== 'undefined') {
590
- const oldSortFields = this.getSortField(session.lastMsgTime)
591
- // 把老的清空
592
- // 重置一下数据
593
- const topFields = [0, 1]
594
- topFields.forEach(topField => {
595
- if (this.data.sessionData[topField] && this.data.sessionData[topField][oldSortFields.day] && this.data.sessionData[topField][oldSortFields.day][oldSortFields.milliseconds]) {
596
- let index = -1
597
- this.data.sessionData[topField][oldSortFields.day][oldSortFields.milliseconds].some((v, i) => {
598
- if (v === session) {
599
- index = i
600
- return true
601
- }
602
- })
603
- if (index >= 0) {
604
- this.data.sessionData[topField][oldSortFields.day][oldSortFields.milliseconds].splice(index, 1)
605
- }
606
- }
607
- if (this.data.sessionGroupData[groupField] && this.data.sessionGroupData[groupField][topField] && this.data.sessionGroupData[groupField][topField][oldSortFields.day] && this.data.sessionGroupData[groupField][topField][oldSortFields.day][oldSortFields.milliseconds]) {
608
- let index = -1
609
- this.data.sessionGroupData[groupField][topField][oldSortFields.day][oldSortFields.milliseconds].some((v, i) => {
610
- if (v === session) {
611
- index = i
612
- return true
613
- }
614
- })
615
- if (index >= 0) {
616
- this.data.sessionGroupData[groupField][topField][oldSortFields.day][oldSortFields.milliseconds].splice(index, 1)
617
- }
618
- }
619
- })
620
- // 按照新的时间来分组排序
621
- Vue.set(session, 'lastMsgTime', lastMsgTime)
622
- const topField = session.stickyOnTop ? 0 : 1 // 0置顶
623
- const sortFields = this.getSortField(session.lastMsgTime)
624
- // 所有的
625
- if (!this.data.sessionData[topField]) {
626
- Vue.set(this.data.sessionData, topField, {})
627
- }
628
- if (!this.data.sessionData[topField][sortFields.day]) {
629
- Vue.set(this.data.sessionData[topField], sortFields.day, {})
630
- }
631
- if (!this.data.sessionData[topField][sortFields.day][sortFields.milliseconds]) {
632
- Vue.set(this.data.sessionData[topField][sortFields.day], sortFields.milliseconds, [])
726
+ if (!nextProps) {
727
+ return session
728
+ }
729
+ const oldGroupField = session[this.groupField] || 'unkonw'
730
+ const nextGroupField = typeof nextProps[this.groupField] === 'undefined' ? oldGroupField : (nextProps[this.groupField] || 'unkonw')
731
+ const shouldReindex = (typeof nextProps.lastMsgTime !== 'undefined' && nextProps.lastMsgTime !== session.lastMsgTime) ||
732
+ (typeof nextProps.stickyOnTop !== 'undefined' && nextProps.stickyOnTop !== session.stickyOnTop) ||
733
+ nextGroupField !== oldGroupField
734
+ if (shouldReindex) {
735
+ this._removeSessionFromDisplayData(sessionId)
736
+ }
737
+ if (typeof nextProps.mute !== 'undefined' || nextGroupField !== oldGroupField) {
738
+ Object.keys(this.data.sessionMuteMap).forEach(groupField => {
739
+ if (this.data.sessionMuteMap[groupField]) {
740
+ Vue.delete(this.data.sessionMuteMap[groupField], sessionId)
633
741
  }
634
- this.data.sessionData[topField][sortFields.day][sortFields.milliseconds].push(session)
635
- // 分组的
636
- if (!this.data.sessionGroupData[groupField]) {
637
- Vue.set(this.data.sessionGroupData, groupField, {})
638
- }
639
- if (!this.data.sessionGroupData[groupField][topField]) {
640
- Vue.set(this.data.sessionGroupData[groupField], topField, {})
641
- }
642
- if (!this.data.sessionGroupData[groupField][topField][sortFields.day]) {
643
- Vue.set(this.data.sessionGroupData[groupField][topField], sortFields.day, {})
644
- }
645
- if (!this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds]) {
646
- Vue.set(this.data.sessionGroupData[groupField][topField][sortFields.day], sortFields.milliseconds, [])
647
- }
648
- this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds].push(session)
649
- }
650
- // 处理未读数量逻辑
651
- if (typeof unreadMsgCount !== 'undefined') {
652
- const origUnreadMsgCount = session.unreadMsgCount || 0
653
- Vue.set(session, 'unreadMsgCount', unreadMsgCount)
654
- // let nowUnreadMsgCount = session.unreadMsgCount || 0
655
- // let diffUnreadMsgCount = nowUnreadMsgCount - origUnreadMsgCount
656
- // if (diffUnreadMsgCount) {
657
- // this.data.sessionUnreadCountMap[groupField] += diffUnreadMsgCount
658
- // }
659
- }
660
- // 处理置顶会话逻辑
661
- if (typeof stickyOnTop !== 'undefined') {
662
- Vue.set(session, 'stickyOnTop', stickyOnTop)
663
- const topField = nextProps.stickyOnTop ? 0 : 1 // 0置顶
664
- // 把已经存在的剔除,先删后插
665
- // 所有的
666
- const sortFields = this.getSortField(session[this.sortField])
667
- // 重置一下数据
668
- const topFields = [0, 1]
669
- topFields.forEach(topField => {
670
- if (this.data.sessionData[topField] && this.data.sessionData[topField][sortFields.day] && this.data.sessionData[topField][sortFields.day][sortFields.milliseconds]) {
671
- let index = -1
672
- this.data.sessionData[topField][sortFields.day][sortFields.milliseconds].some((v, i) => {
673
- if (v === session) {
674
- index = i
675
- return true
676
- }
677
- })
678
- if (index >= 0) {
679
- this.data.sessionData[topField][sortFields.day][sortFields.milliseconds].splice(index, 1)
680
- }
681
- }
682
- if (this.data.sessionGroupData[groupField] && this.data.sessionGroupData[groupField][topField] && this.data.sessionGroupData[groupField][topField][sortFields.day] && this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds]) {
683
- let index = -1
684
- this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds].some((v, i) => {
685
- if (v === session) {
686
- index = i
687
- return true
688
- }
689
- })
690
- if (index >= 0) {
691
- this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds].splice(index, 1)
692
- }
693
- }
694
- })
695
- // 所有的
696
- if (!this.data.sessionData[topField]) {
697
- Vue.set(this.data.sessionData, topField, {})
698
- }
699
- if (!this.data.sessionData[topField][sortFields.day]) {
700
- Vue.set(this.data.sessionData[topField], sortFields.day, {})
701
- }
702
- if (!this.data.sessionData[topField][sortFields.day][sortFields.milliseconds]) {
703
- Vue.set(this.data.sessionData[topField][sortFields.day], sortFields.milliseconds, [])
704
- }
705
- this.data.sessionData[topField][sortFields.day][sortFields.milliseconds].push(session)
706
- // 分组的
707
- if (!this.data.sessionGroupData[groupField]) {
708
- Vue.set(this.data.sessionGroupData, groupField, {})
709
- }
710
- if (!this.data.sessionGroupData[groupField][topField]) {
711
- Vue.set(this.data.sessionGroupData[groupField], topField, {})
712
- }
713
- if (!this.data.sessionGroupData[groupField][topField][sortFields.day]) {
714
- Vue.set(this.data.sessionGroupData[groupField][topField], sortFields.day, {})
715
- }
716
- if (!this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds]) {
717
- Vue.set(this.data.sessionGroupData[groupField][topField][sortFields.day], sortFields.milliseconds, [])
718
- }
719
- this.data.sessionGroupData[groupField][topField][sortFields.day][sortFields.milliseconds].push(session)
742
+ })
743
+ }
744
+ Object.keys(nextProps).forEach(key => {
745
+ if (session[key] !== nextProps[key]) {
746
+ Vue.set(session, key, nextProps[key])
720
747
  }
721
- // 处理免打扰
722
- if (typeof mute !== 'undefined') {
723
- Vue.set(session, 'mute', mute)
724
- if (mute) {
725
- if (!this.data.sessionMuteMap[groupField]) {
726
- Vue.set(this.data.sessionMuteMap, groupField, {})
727
- }
728
- if (!this.data.sessionMuteMap[groupField][session.id]) {
729
- Vue.set(this.data.sessionMuteMap[groupField], session.id, session)
730
- }
731
- } else {
732
- if (this.data.sessionMuteMap[groupField]) {
733
- Vue.delete(this.data.sessionMuteMap[groupField], session.id)
734
- }
735
- }
748
+ })
749
+ if (shouldReindex) {
750
+ this._insertSessionIntoDisplayData(session)
751
+ }
752
+ const groupField = session[this.groupField] || 'unkonw'
753
+ if (session.mute) {
754
+ if (!this.data.sessionMuteMap[groupField]) {
755
+ Vue.set(this.data.sessionMuteMap, groupField, {})
736
756
  }
757
+ Vue.set(this.data.sessionMuteMap[groupField], session.id, session)
737
758
  }
759
+ return session
738
760
  }
739
761
 
740
762
  /**
@@ -963,9 +985,12 @@ export default class ClientChatSession {
963
985
  }
964
986
 
965
987
  reset () {
988
+ this.stopGetSessionPollRequests()
966
989
  this.lastUpdateTime = null
967
990
  this.lastUpdateSession = null
968
991
  this.lastSession = null
992
+ this._lastUpdateSessionMap = {}
993
+ this._reverseLastUpdateSessionMap = {}
969
994
  this.data.sessionData = {}
970
995
  this.data.sessionGroupData = {}
971
996
  this.data.sessionMuteMap = {}
@@ -5,7 +5,6 @@ import ClientChatContacts from './client-chat-concats.js'
5
5
  import ClientChatAccount from './client-chat-account.js'
6
6
  import ClientChatSocket from './client-chat-socket.js'
7
7
  import { createSessionId } from './utils.js'
8
- import { createPollRequest } from '../../../utils/util.js'
9
8
  import Event from '../../../utils/event.js'
10
9
 
11
10
  const CONNECT_STATUS = {
@@ -22,8 +21,6 @@ class ClientChat {
22
21
  return this.data.connectStatus === CONNECT_STATUS.Loading
23
22
  }
24
23
 
25
- _sessionPollRequestMap = {}
26
-
27
24
  constructor (options) {
28
25
 
29
26
  options = Object.assign({
@@ -79,6 +76,14 @@ class ClientChat {
79
76
  getSessionMethod: options.getSessionMethod,
80
77
  loadSessionDataMethod: options.loadSessionDataMethod,
81
78
  deleteSessionMethod: options.deleteSessionMethod,
79
+ onAddSession: ({ session, unreadDelta }) => {
80
+ if (!unreadDelta) {
81
+ return
82
+ }
83
+ this.account.updateAccountUnreadMessageNum(session.qwAccountId, ({ unreadMesasgeNum }) => {
84
+ return (unreadMesasgeNum || 0) + unreadDelta
85
+ })
86
+ },
82
87
  onSessionReadChange: ({ session, oldUnreadMsgCount }) => {
83
88
  this.account.updateAccountUnreadMessageNum(session.qwAccountId, ({ unreadMesasgeNum }) => {
84
89
  return Math.max(0, unreadMesasgeNum - oldUnreadMsgCount)
@@ -90,64 +95,69 @@ class ClientChat {
90
95
  sortField: 'sendTime',
91
96
  clientChat: this,
92
97
  checkMessageSendResultMethod: options.checkMessageSendResultMethod,
93
- onAddMessageSuccess: ({ data }) => {
94
- const accountId = this.getLoginAccountIdMethod ? this.getLoginAccountIdMethod() : data.qwAccountId
98
+ onAddMessageSuccess: ({ data, isBeforeLastMessage }) => {
99
+ const accountId = options.getLoginAccountIdMethod ? options.getLoginAccountIdMethod() : data.qwAccountId
95
100
  let sessionId = createSessionId(accountId, data.contactId)
96
101
  // 更新会话
97
102
  if (!sessionId) {
98
103
  return
99
104
  }
105
+ if (isBeforeLastMessage) {
106
+ return
107
+ }
100
108
  const localSession = this.session.getSessionByLocal(sessionId)
101
109
  if (!localSession) {
102
- if (this._sessionPollRequestMap[sessionId]) {
103
- this._sessionPollRequestMap[sessionId].stop()
104
- }
105
- this._sessionPollRequestMap[sessionId] = createPollRequest(({ done, fail }) => {
106
- return this.session.getSession(sessionId).then(done)
107
- })
108
- this._sessionPollRequestMap[sessionId].start().then((rs) => {
109
- // 后端更新会话是异步过程,返回的会话信息可能还未包含当前消息
110
- if (rs && rs.data && !rs.data.unreadMsgCount) {
111
- rs.data.unreadMsgCount = data.isSend ? 0 : 1
112
- rs.data.lastMsgContent = data.content
113
- rs.data.lastMsgType = data.msgType
114
- rs.data.lastMsgTime = data.sendTime
115
- rs.data.lastMsgId = data.id
116
- rs.data.lastUpdateTime = data.updateDate
110
+ return this.session.getSession(sessionId, (rs, context) => {
111
+ if (rs && rs.data) {
112
+ const isAfterServerMessage = data.sendTime > context.baseLastMsgTime
113
+ const isNewerMessage = data.sendTime > (rs.data.lastMsgTime || 0)
114
+ if (isNewerMessage) {
115
+ rs.data.lastMsgContent = data.content
116
+ rs.data.lastMsgType = data.msgType
117
+ rs.data.lastMsgTime = data.sendTime
118
+ rs.data.lastMsgId = data.id
119
+ rs.data.lastUpdateTime = data.updateDate
120
+ }
121
+ const isCurrentSession = this.session.currentSession && this.session.currentSession.id === sessionId
122
+ // 服务端返回的会话还没有包含当前消息时,本地补充会话未读数
123
+ if (!data.isSend && isAfterServerMessage) {
124
+ rs.data.unreadMsgCount = isCurrentSession ? 0 : (rs.data.unreadMsgCount || 0) + 1
125
+ }
126
+ // 账号未读只累计本次轮询期间新增的消息,避免重复累计服务端已有的未读数
127
+ if (!data.isSend && !(isAfterServerMessage && isCurrentSession)) {
128
+ context.accountUnreadDelta += 1
129
+ }
117
130
  }
118
- // 更新账号未读消息数量
119
- this.account.updateAccountUnreadMessageNum(rs.data.qwAccountId, ({ unreadMesasgeNum }) => {
120
- return unreadMesasgeNum += (rs.data.unreadMsgCount || 0)
121
- })
122
- }).finally(() => {
123
- delete this._sessionPollRequestMap[sessionId]
124
- })
131
+ return rs
132
+ }).catch(() => {})
125
133
  } else {
126
134
  this.session.updateSession(sessionId, ({ session }) => {
127
- let unreadMsgCount = session.unreadMsgCount
128
- if (!data.isSend) {
129
- unreadMsgCount = unreadMsgCount + 1
130
- }
131
- // 如果是当前会话,那么未读消息需要设置为0
132
- if (this.session.currentSession && this.session.currentSession.id === sessionId) {
133
- unreadMsgCount = 0
134
- // 标记已读,并且设置未读数量为0
135
- this.session.setSessionRead(sessionId)
136
- } else {
137
- // 更新账号未读消息数量
138
- this.account.updateAccountUnreadMessageNum(session.qwAccountId, ({ unreadMesasgeNum }) => {
139
- return unreadMesasgeNum += 1
140
- })
135
+ const isNewerMessage = data.sendTime > (session.lastMsgTime || 0)
136
+ if (!isNewerMessage) {
137
+ return {}
141
138
  }
142
- const nextSessin = {
139
+ const nextSession = {
143
140
  lastMsgContent: data.content,
144
141
  lastMsgType: data.msgType,
145
142
  lastMsgTime: data.sendTime,
146
143
  lastMsgId: data.id,
147
144
  lastUpdateTime: data.updateDate,
148
- unreadMsgCount
145
+ unreadMsgCount: session.unreadMsgCount || 0
149
146
  }
150
- return nextSessin
147
+ if (!data.isSend) {
148
+ if (this.session.currentSession && this.session.currentSession.id === sessionId) {
149
+ // 标记已读
150
+ nextSession.unreadMsgCount = 0
151
+ this.session.setSessionRead(sessionId)
152
+ } else {
153
+ nextSession.unreadMsgCount += 1
154
+ // 更新账号未读消息数量
155
+ this.account.updateAccountUnreadMessageNum(session.qwAccountId, ({ unreadMesasgeNum }) => {
156
+ return (unreadMesasgeNum || 0) + 1
157
+ })
158
+ }
159
+ }
160
+ return nextSession
151
161
  })
152
162
  }
153
163
  },
@@ -170,65 +180,70 @@ class ClientChat {
170
180
  sortField: 'sendTime',
171
181
  clientChat: this,
172
182
  checkMessageSendResultMethod: options.checkMessageSendResultMethod,
173
- onAddMessageSuccess: ({ data }) => {
174
- const accountId = this.getLoginAccountIdMethod ? this.getLoginAccountIdMethod() : data.qwAccountId
183
+ onAddMessageSuccess: ({ data, isBeforeLastMessage }) => {
184
+ const accountId = options.getLoginAccountIdMethod ? options.getLoginAccountIdMethod() : data.qwAccountId
175
185
  let sessionId = createSessionId(accountId, data.roomId)
176
186
  // 更新会话
177
187
  if (!sessionId) {
178
188
  return
179
189
  }
190
+ if (isBeforeLastMessage) {
191
+ return
192
+ }
180
193
  // 更新会话未读消息数量
181
194
  const localSession = this.session.getSessionByLocal(sessionId)
182
195
  if (!localSession) {
183
- if (this._sessionPollRequestMap[sessionId]) {
184
- this._sessionPollRequestMap[sessionId].stop()
185
- }
186
- this._sessionPollRequestMap[sessionId] = createPollRequest(({ done, fail }) => {
187
- return this.session.getSession(sessionId).then(done)
188
- })
189
- this._sessionPollRequestMap[sessionId].start().then((rs) => {
190
- // 后端更新会话是异步过程,返回的会话信息可能还未包含当前消息
191
- if (rs && rs.data && !rs.data.unreadMsgCount) {
192
- rs.data.unreadMsgCount = data.isSend ? 0 : 1
193
- rs.data.lastMsgContent = data.content
194
- rs.data.lastMsgType = data.msgType
195
- rs.data.lastMsgTime = data.sendTime
196
- rs.data.lastMsgId = data.id
197
- rs.data.lastUpdateTime = data.updateDate
196
+ return this.session.getSession(sessionId, (rs, context) => {
197
+ if (rs && rs.data) {
198
+ const isAfterServerMessage = data.sendTime > context.baseLastMsgTime
199
+ const isNewerMessage = data.sendTime > (rs.data.lastMsgTime || 0)
200
+ if (isNewerMessage) {
201
+ rs.data.lastMsgContent = data.content
202
+ rs.data.lastMsgType = data.msgType
203
+ rs.data.lastMsgTime = data.sendTime
204
+ rs.data.lastMsgId = data.id
205
+ rs.data.lastUpdateTime = data.updateDate
206
+ }
207
+ const isCurrentSession = this.session.currentSession && this.session.currentSession.id === sessionId
208
+ // 服务端返回的会话还没有包含当前消息时,本地补充会话未读数
209
+ if (!data.isSend && isAfterServerMessage) {
210
+ rs.data.unreadMsgCount = isCurrentSession ? 0 : (rs.data.unreadMsgCount || 0) + 1
211
+ }
212
+ // 账号未读只累计本次轮询期间新增的消息,避免重复累计服务端已有的未读数
213
+ if (!data.isSend && !(isAfterServerMessage && isCurrentSession)) {
214
+ context.accountUnreadDelta += 1
215
+ }
198
216
  }
199
- // 更新账号未读消息数量
200
- this.account.updateAccountUnreadMessageNum(rs.data.qwAccountId, ({ unreadMesasgeNum }) => {
201
- return unreadMesasgeNum += (rs.data.unreadMsgCount || 0)
202
- })
203
- }).finally(() => {
204
- delete this._sessionPollRequestMap[sessionId]
205
- })
217
+ return rs
218
+ }).catch(() => {})
206
219
  } else {
207
220
  this.session.updateSession(sessionId, ({ session }) => {
208
- let unreadMsgCount = session.unreadMsgCount
209
- if (!data.isSend) {
210
- unreadMsgCount = unreadMsgCount + 1
221
+ const isNewerMessage = data.sendTime > (session.lastMsgTime || 0)
222
+ if (!isNewerMessage) {
223
+ return {}
211
224
  }
212
- // 如果是当前会话,那么未读消息需要设置为0
213
- if (this.session.currentSession && this.session.currentSession.id === sessionId) {
214
- unreadMsgCount = 0
215
- // 标记已读,并且设置未读数量为0
216
- this.session.setSessionRead(sessionId)
217
- } else {
218
- // 更新账号未读消息数量
219
- this.account.updateAccountUnreadMessageNum(session.qwAccountId, ({ unreadMesasgeNum }) => {
220
- return unreadMesasgeNum += 1
221
- })
222
- }
223
- const nextSessin = {
225
+ const nextSession = {
224
226
  lastMsgContent: data.content,
225
227
  lastMsgType: data.msgType,
226
228
  lastMsgTime: data.sendTime,
227
229
  lastMsgId: data.id,
228
230
  lastUpdateTime: data.updateDate,
229
- unreadMsgCount
231
+ unreadMsgCount: session.unreadMsgCount || 0
230
232
  }
231
- return nextSessin
233
+ if (!data.isSend) {
234
+ if (this.session.currentSession && this.session.currentSession.id === sessionId) {
235
+ // 标记已读
236
+ nextSession.unreadMsgCount = 0
237
+ this.session.setSessionRead(sessionId)
238
+ } else {
239
+ nextSession.unreadMsgCount += 1
240
+ // 更新账号未读消息数量
241
+ this.account.updateAccountUnreadMessageNum(session.qwAccountId, ({ unreadMesasgeNum }) => {
242
+ return (unreadMesasgeNum || 0) + 1
243
+ })
244
+ }
245
+ }
246
+ return nextSession
232
247
  })
233
248
  }
234
249
  },
@@ -620,12 +635,7 @@ class ClientChat {
620
635
 
621
636
  disconnect () {
622
637
  this.data.connectStatus = CONNECT_STATUS.Normal
623
- if (this._sessionPollRequestMap) {
624
- Object.keys(this._sessionPollRequestMap).forEach(key => {
625
- this._sessionPollRequestMap[key].stop()
626
- })
627
- this._sessionPollRequestMap = {}
628
- }
638
+ this.session.stopGetSessionPollRequests()
629
639
  this.contacts.reset()
630
640
  this.account.reset()
631
641
  this.friendMessage.reset()