chatStore.js 11 KB

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