chatStore.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. import {
  2. MESSAGE_TYPE,
  3. MESSAGE_STATUS
  4. } from '@/common/enums.js';
  5. import userStore from './userStore';
  6. /*
  7. uniapp性能优化:
  8. 1.由于uniapp渲染消息性能非常拉胯,所以先把离线消息存储到cacheChats,等
  9. 待所有离线消息拉取完成后,再统一进行渲染
  10. 2.在vuex中对数组进行unshift,splice特别卡,所以删除会话、会话置顶、删
  11. 除消息等操作进行优化,不通过unshift,splice实现,改造方案如下:
  12. 删除会话: 通过delete标志判断是否删除
  13. 删除消息:通过delete标志判断是否删除
  14. 会话置顶:通过lastSendTime排序确定会话顺序
  15. */
  16. let cacheChats = [];
  17. export default {
  18. state: {
  19. chats: [],
  20. privateMsgMaxId: 0,
  21. groupMsgMaxId: 0,
  22. loadingPrivateMsg: false,
  23. loadingGroupMsg: false,
  24. },
  25. mutations: {
  26. initChats(state, chatsData) {
  27. cacheChats = [];
  28. state.chats = [];
  29. for (let chat of chatsData.chats) {
  30. // 已删除的会话直接丢弃
  31. if (chat.delete) {
  32. continue;
  33. }
  34. // 暂存至缓冲区
  35. cacheChats.push(JSON.parse(JSON.stringify(chat)));
  36. // 加载期间显示只前15个会话做做样子,一切都为了加快初始化时间
  37. if (state.chats.length < 15) {
  38. chat.messages = [];
  39. state.chats.push(chat);
  40. }
  41. }
  42. state.privateMsgMaxId = chatsData.privateMsgMaxId || 0;
  43. state.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
  44. // 防止图片一直处在加载中状态
  45. cacheChats.forEach((chat) => {
  46. chat.messages.forEach((msg) => {
  47. if (msg.loadStatus == "loading") {
  48. msg.loadStatus = "fail"
  49. }
  50. })
  51. })
  52. },
  53. openChat(state, chatInfo) {
  54. let chats = this.getters.findChats();
  55. let chat = null;
  56. for (let idx in chats) {
  57. if (chats[idx].type == chatInfo.type &&
  58. chats[idx].targetId === chatInfo.targetId) {
  59. chat = chats[idx];
  60. chat.delete = false;
  61. // 放置头部
  62. this.commit("moveTop", idx)
  63. break;
  64. }
  65. }
  66. // 创建会话
  67. if (chat == null) {
  68. chat = {
  69. targetId: chatInfo.targetId,
  70. type: chatInfo.type,
  71. showName: chatInfo.showName,
  72. headImage: chatInfo.headImage,
  73. lastContent: "",
  74. lastSendTime: new Date().getTime(),
  75. unreadCount: 0,
  76. messages: [],
  77. atMe: false,
  78. atAll: false,
  79. delete: false
  80. };
  81. chats.push(chat);
  82. this.commit("moveTop", chats.length - 1)
  83. }
  84. },
  85. activeChat(state, idx) {
  86. let chats = this.getters.findChats();
  87. if (idx >= 0) {
  88. chats[idx].unreadCount = 0;
  89. }
  90. },
  91. resetUnreadCount(state, chatInfo) {
  92. let chats = this.getters.findChats();
  93. for (let idx in chats) {
  94. if (chats[idx].type == chatInfo.type &&
  95. chats[idx].targetId == chatInfo.targetId) {
  96. chats[idx].unreadCount = 0;
  97. chats[idx].atMe = false;
  98. chats[idx].atAll = false;
  99. }
  100. }
  101. this.commit("saveToStorage");
  102. },
  103. readedMessage(state, pos) {
  104. let chats = this.getters.findChats();
  105. for (let idx in chats) {
  106. if (chats[idx].type == 'PRIVATE' &&
  107. chats[idx].targetId == pos.friendId) {
  108. chats[idx].messages.forEach((m) => {
  109. if (m.selfSend && m.status != MESSAGE_STATUS.RECALL) {
  110. // pos.maxId为空表示整个会话已读
  111. if (!pos.maxId || m.id <= pos.maxId) {
  112. m.status = MESSAGE_STATUS.READED
  113. }
  114. }
  115. })
  116. }
  117. }
  118. this.commit("saveToStorage");
  119. },
  120. removeChat(state, idx) {
  121. let chats = this.getters.findChats();
  122. chats[idx].delete = true;
  123. this.commit("saveToStorage");
  124. },
  125. removePrivateChat(state, userId) {
  126. let chats = this.getters.findChats();
  127. for (let idx in chats) {
  128. if (chats[idx].type == 'PRIVATE' &&
  129. chats[idx].targetId == userId) {
  130. this.commit("removeChat", idx);
  131. }
  132. }
  133. },
  134. moveTop(state, idx) {
  135. let chats = this.getters.findChats();
  136. let chat = chats[idx];
  137. // 最新的时间会显示在顶部
  138. chat.lastSendTime = new Date().getTime();
  139. this.commit("saveToStorage");
  140. },
  141. insertMessage(state, msgInfo) {
  142. // 获取对方id或群id
  143. let type = msgInfo.groupId ? 'GROUP' : 'PRIVATE';
  144. // 记录消息的最大id
  145. if (msgInfo.id && type == "PRIVATE" && msgInfo.id > state.privateMsgMaxId) {
  146. state.privateMsgMaxId = msgInfo.id;
  147. }
  148. if (msgInfo.id && type == "GROUP" && msgInfo.id > state.groupMsgMaxId) {
  149. state.groupMsgMaxId = msgInfo.id;
  150. }
  151. // 如果是已存在消息,则覆盖旧的消息数据
  152. let chat = this.getters.findChat(msgInfo);
  153. let message = this.getters.findMessage(chat, msgInfo);
  154. if (message) {
  155. Object.assign(message, msgInfo);
  156. // 撤回消息需要显示
  157. if (msgInfo.type == MESSAGE_TYPE.RECALL) {
  158. chat.lastContent = msgInfo.content;
  159. }
  160. this.commit("saveToStorage");
  161. return;
  162. }
  163. // 会话列表内容
  164. if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
  165. chat.lastContent = "[图片]";
  166. } else if (msgInfo.type == MESSAGE_TYPE.FILE) {
  167. chat.lastContent = "[文件]";
  168. } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) {
  169. chat.lastContent = "[语音]";
  170. } else if (msgInfo.type == MESSAGE_TYPE.TEXT || msgInfo.type == MESSAGE_TYPE.RECALL) {
  171. chat.lastContent = msgInfo.content;
  172. } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) {
  173. chat.lastContent = "[语音通话]";
  174. } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) {
  175. chat.lastContent = "[视频通话]";
  176. }
  177. chat.lastSendTime = msgInfo.sendTime;
  178. chat.sendNickName = msgInfo.sendNickName;
  179. // 未读加1
  180. if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED &&
  181. msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
  182. chat.unreadCount++;
  183. }
  184. // 是否有人@我
  185. if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds &&
  186. msgInfo.status != MESSAGE_STATUS.READED) {
  187. let userId = userStore.state.userInfo.id;
  188. if (msgInfo.atUserIds.indexOf(userId) >= 0) {
  189. chat.atMe = true;
  190. }
  191. if (msgInfo.atUserIds.indexOf(-1) >= 0) {
  192. chat.atAll = true;
  193. }
  194. }
  195. // 间隔大于10分钟插入时间显示
  196. if (!chat.lastTimeTip || (chat.lastTimeTip < msgInfo.sendTime - 600 * 1000)) {
  197. chat.messages.push({
  198. sendTime: msgInfo.sendTime,
  199. type: MESSAGE_TYPE.TIP_TIME,
  200. });
  201. chat.lastTimeTip = msgInfo.sendTime;
  202. }
  203. // 根据id顺序插入,防止消息乱序
  204. let insertPos = chat.messages.length;
  205. // 防止 图片、文件 在发送方 显示 在顶端 因为还没存库,id=0
  206. if (msgInfo.id && msgInfo.id > 0) {
  207. for (let idx in chat.messages) {
  208. if (chat.messages[idx].id && msgInfo.id < chat.messages[idx].id) {
  209. insertPos = idx;
  210. console.log(`消息出现乱序,位置:${chat.messages.length},修正至:${insertPos}`);
  211. break;
  212. }
  213. }
  214. }
  215. if (insertPos == chat.messages.length) {
  216. // 这种赋值效率最高
  217. chat.messages[insertPos] = msgInfo;
  218. } else {
  219. chat.messages.splice(insertPos, 0, msgInfo);
  220. }
  221. this.commit("saveToStorage");
  222. },
  223. updateMessage(state, msgInfo) {
  224. // 获取对方id或群id
  225. let chat = this.getters.findChat(msgInfo);
  226. let message = this.getters.findMessage(chat, msgInfo);
  227. if (message) {
  228. // 属性拷贝
  229. Object.assign(message, msgInfo);
  230. this.commit("saveToStorage");
  231. }
  232. },
  233. deleteMessage(state, msgInfo) {
  234. // 获取对方id或群id
  235. let chat = this.getters.findChat(msgInfo);
  236. for (let idx in chat.messages) {
  237. // 已经发送成功的,根据id删除
  238. if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
  239. chat.messages[idx].delete = true;
  240. break;
  241. }
  242. // 正在发送中的消息可能没有id,根据发送时间删除
  243. if (msgInfo.selfSend && chat.messages[idx].selfSend &&
  244. chat.messages[idx].sendTime == msgInfo.sendTime) {
  245. chat.messages[idx].delete = true;
  246. break;
  247. }
  248. }
  249. this.commit("saveToStorage");
  250. },
  251. updateChatFromFriend(state, friend) {
  252. let chats = this.getters.findChats();
  253. for (let i in chats) {
  254. let chat = chats[i];
  255. if (chat.type == 'PRIVATE' && chat.targetId == friend.id) {
  256. chat.headImage = friend.headImageThumb;
  257. chat.showName = friend.nickName;
  258. break;
  259. }
  260. }
  261. this.commit("saveToStorage");
  262. },
  263. updateChatFromGroup(state, group) {
  264. let chats = this.getters.findChats();
  265. for (let i in chats) {
  266. let chat = chats[i];
  267. if (chat.type == 'GROUP' && chat.targetId == group.id) {
  268. chat.headImage = group.headImageThumb;
  269. chat.showName = group.remark;
  270. break;
  271. }
  272. }
  273. this.commit("saveToStorage");
  274. },
  275. loadingPrivateMsg(state, loading) {
  276. state.loadingPrivateMsg = loading;
  277. if (!this.getters.isLoading()) {
  278. this.commit("refreshChats")
  279. }
  280. },
  281. loadingGroupMsg(state, loading) {
  282. state.loadingGroupMsg = loading;
  283. if (!this.getters.isLoading()) {
  284. this.commit("refreshChats")
  285. }
  286. },
  287. refreshChats(state) {
  288. // 排序
  289. cacheChats.sort((chat1, chat2) => {
  290. return chat2.lastSendTime - chat1.lastSendTime;
  291. });
  292. // 将消息一次性装载回来
  293. state.chats = cacheChats;
  294. this.commit("saveToStorage");
  295. },
  296. saveToStorage(state) {
  297. // 加载中不保存,防止卡顿
  298. if (this.getters.isLoading()) {
  299. return;
  300. }
  301. let userId = userStore.state.userInfo.id;
  302. let key = "chats-app-" + userId;
  303. let chatsData = {
  304. privateMsgMaxId: state.privateMsgMaxId,
  305. groupMsgMaxId: state.groupMsgMaxId,
  306. chats: state.chats
  307. }
  308. uni.setStorage({
  309. key: key,
  310. data: chatsData ,
  311. })
  312. },
  313. clear(state) {
  314. cacheChats = [];
  315. state.chats = [];
  316. state.privateMsgMaxId = 0;
  317. state.groupMsgMaxId = 0;
  318. state.loadingPrivateMsg = false;
  319. state.loadingGroupMsg = false;
  320. }
  321. },
  322. actions: {
  323. loadChat(context) {
  324. return new Promise((resolve, reject) => {
  325. let userId = userStore.state.userInfo.id;
  326. uni.getStorage({
  327. key: "chats-app-" + userId,
  328. success(res) {
  329. context.commit("initChats", res.data);
  330. resolve()
  331. },
  332. fail(e) {
  333. resolve()
  334. }
  335. });
  336. })
  337. }
  338. },
  339. getters: {
  340. isLoading: (state) => () => {
  341. return state.loadingPrivateMsg || state.loadingGroupMsg
  342. },
  343. findChats: (state, getters) => () => {
  344. return getters.isLoading() ? cacheChats : state.chats;
  345. },
  346. findChatIdx: (state, getters) => (chat) => {
  347. let chats = getters.findChats();
  348. for (let idx in chats) {
  349. if (chats[idx].type == chat.type &&
  350. chats[idx].targetId === chat.targetId) {
  351. chat = state.chats[idx];
  352. return idx;
  353. }
  354. }
  355. },
  356. findChat: (state, getters) => (msgInfo) => {
  357. let chats = getters.findChats();
  358. // 获取对方id或群id
  359. let type = msgInfo.groupId ? 'GROUP' : 'PRIVATE';
  360. let targetId = msgInfo.groupId ? msgInfo.groupId : msgInfo.selfSend ? msgInfo.recvId : msgInfo.sendId;
  361. let chat = null;
  362. for (let idx in chats) {
  363. if (chats[idx].type == type &&
  364. chats[idx].targetId === targetId) {
  365. chat = chats[idx];
  366. break;
  367. }
  368. }
  369. return chat;
  370. },
  371. findMessage: (state) => (chat, msgInfo) => {
  372. if (!chat) {
  373. return null;
  374. }
  375. for (let idx in chat.messages) {
  376. // 通过id判断
  377. if (msgInfo.id && chat.messages[idx].id == msgInfo.id) {
  378. return chat.messages[idx];
  379. }
  380. // 正在发送中的消息可能没有id,只有tmpId
  381. if (msgInfo.tmpId && chat.messages[idx].tmpId &&
  382. chat.messages[idx].tmpId == msgInfo.tmpId) {
  383. console.log("chat.messages[idx].tmpId == msgInfo.tmpId")
  384. return chat.messages[idx];
  385. }
  386. }
  387. }
  388. }
  389. }