chatStore.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. import { defineStore } from 'pinia';
  2. import { MESSAGE_TYPE, MESSAGE_STATUS } from '@/common/enums.js';
  3. import useUserStore from './userStore';
  4. import UNI_APP from '../.env';
  5. let cacheChats = [];
  6. export default defineStore('chatStore', {
  7. state: () => {
  8. return {
  9. chats: [],
  10. privateMsgMaxId: 0,
  11. groupMsgMaxId: 0,
  12. loadingPrivateMsg: false,
  13. loadingGroupMsg: false
  14. }
  15. },
  16. actions: {
  17. initChats(chatsData) {
  18. cacheChats = [];
  19. this.chats = [];
  20. for (let chat of chatsData.chats) {
  21. chat.stored = false;
  22. // 清理多余的消息,避免消息过多导致卡顿
  23. if (UNI_APP.MAX_MESSAGE_SIZE > 0 && chat.messages.length > UNI_APP.MAX_MESSAGE_SIZE) {
  24. let idx = chat.messages.length - UNI_APP.MAX_MESSAGE_SIZE;
  25. chat.messages = chat.messages.slice(idx);
  26. }
  27. // 暂存至缓冲区
  28. cacheChats.push(JSON.parse(JSON.stringify(chat)));
  29. // 加载期间显示只前15个会话做做样子,一切都为了加快初始化时间
  30. if (this.chats.length < 15) {
  31. this.chats.push(chat);
  32. }
  33. }
  34. this.privateMsgMaxId = chatsData.privateMsgMaxId || 0;
  35. this.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
  36. // 防止图片一直处在加载中状态
  37. cacheChats.forEach((chat) => {
  38. chat.messages.forEach((msg) => {
  39. if (msg.loadStatus == "loading") {
  40. msg.loadStatus = "fail"
  41. }
  42. })
  43. })
  44. },
  45. openChat(chatInfo) {
  46. let chats = this.curChats;
  47. let chat = null;
  48. for (let idx in chats) {
  49. if (chats[idx].type == chatInfo.type &&
  50. chats[idx].targetId === chatInfo.targetId) {
  51. chat = chats[idx];
  52. // 放置头部
  53. this.moveTop(idx)
  54. break;
  55. }
  56. }
  57. // 创建会话
  58. if (chat == null) {
  59. chat = {
  60. targetId: chatInfo.targetId,
  61. type: chatInfo.type,
  62. showName: chatInfo.showName,
  63. headImage: chatInfo.headImage,
  64. lastContent: "",
  65. lastSendTime: new Date().getTime(),
  66. unreadCount: 0,
  67. hotMinIdx: 0,
  68. messages: [],
  69. atMe: false,
  70. atAll: false,
  71. stored: false
  72. };
  73. chats.unshift(chat);
  74. this.saveToStorage();
  75. }
  76. },
  77. activeChat(idx) {
  78. let chats = this.curChats;
  79. if (idx >= 0) {
  80. chats[idx].unreadCount = 0;
  81. }
  82. },
  83. resetUnreadCount(chatInfo) {
  84. let chats = this.curChats;
  85. for (let idx in chats) {
  86. if (chats[idx].type == chatInfo.type &&
  87. chats[idx].targetId == chatInfo.targetId) {
  88. chats[idx].unreadCount = 0;
  89. chats[idx].atMe = false;
  90. chats[idx].atAll = false;
  91. chats[idx].stored = false;
  92. this.saveToStorage();
  93. }
  94. }
  95. },
  96. readedMessage(pos) {
  97. let chat = this.findChatByFriend(pos.friendId);
  98. if (!chat) return;
  99. chat.messages.forEach((m) => {
  100. if (m.id && m.selfSend && m.status < MESSAGE_STATUS.RECALL) {
  101. // pos.maxId为空表示整个会话已读
  102. if (!pos.maxId || m.id <= pos.maxId) {
  103. m.status = MESSAGE_STATUS.READED
  104. chat.stored = false;
  105. }
  106. }
  107. })
  108. if (!chat.stored) {
  109. this.saveToStorage();
  110. }
  111. },
  112. removeChat(idx) {
  113. let chats = this.curChats;
  114. chats[idx].delete = true;
  115. chats[idx].stored = false;
  116. this.saveToStorage();
  117. },
  118. removePrivateChat(userId) {
  119. let chats = this.curChats;
  120. for (let idx in chats) {
  121. if (chats[idx].type == 'PRIVATE' &&
  122. chats[idx].targetId == userId) {
  123. this.removeChat(idx);
  124. }
  125. }
  126. },
  127. removeGroupChat(groupId) {
  128. let chats = this.curChats;
  129. for (let idx in chats) {
  130. if (chats[idx].type == 'GROUP' &&
  131. chats[idx].targetId == groupId) {
  132. this.removeChat(idx);
  133. }
  134. }
  135. },
  136. moveTop(idx) {
  137. if (this.isLoading()) {
  138. return;
  139. }
  140. let chats = this.curChats;
  141. if (idx > 0) {
  142. let chat = chats[idx];
  143. chats.splice(idx, 1);
  144. chats.unshift(chat);
  145. chat.lastSendTime = new Date().getTime();
  146. chat.stored = false;
  147. this.saveToStorage();
  148. }
  149. },
  150. insertMessage(msgInfo, chatInfo) {
  151. // 获取对方id或群id
  152. let type = chatInfo.type;
  153. // 记录消息的最大id
  154. if (msgInfo.id && type == "PRIVATE" && msgInfo.id > this.privateMsgMaxId) {
  155. this.privateMsgMaxId = msgInfo.id;
  156. }
  157. if (msgInfo.id && type == "GROUP" && msgInfo.id > this.groupMsgMaxId) {
  158. this.groupMsgMaxId = msgInfo.id;
  159. }
  160. // 如果是已存在消息,则覆盖旧的消息数据
  161. let chat = this.findChat(chatInfo);
  162. let message = this.findMessage(chat, msgInfo);
  163. if (message) {
  164. Object.assign(message, msgInfo);
  165. chat.stored = false;
  166. this.saveToStorage();
  167. return;
  168. }
  169. // 会话列表内容
  170. if (msgInfo.type == MESSAGE_TYPE.IMAGE) {
  171. chat.lastContent = "[图片]";
  172. } else if (msgInfo.type == MESSAGE_TYPE.FILE) {
  173. chat.lastContent = "[文件]";
  174. } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) {
  175. chat.lastContent = "[语音]";
  176. } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) {
  177. chat.lastContent = "[语音通话]";
  178. } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) {
  179. chat.lastContent = "[视频通话]";
  180. } else if (msgInfo.type == MESSAGE_TYPE.TEXT ||
  181. msgInfo.type == MESSAGE_TYPE.RECALL ||
  182. msgInfo.type == MESSAGE_TYPE.TIP_TEXT) {
  183. chat.lastContent = msgInfo.content;
  184. }
  185. chat.lastSendTime = msgInfo.sendTime;
  186. chat.sendNickName = msgInfo.sendNickName;
  187. // 未读加1
  188. if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED &&
  189. msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
  190. chat.unreadCount++;
  191. }
  192. // 是否有人@我
  193. if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds &&
  194. msgInfo.status != MESSAGE_STATUS.READED) {
  195. const userStore = useUserStore();
  196. let userId = userStore.userInfo.id;
  197. if (msgInfo.atUserIds.indexOf(userId) >= 0) {
  198. chat.atMe = true;
  199. }
  200. if (msgInfo.atUserIds.indexOf(-1) >= 0) {
  201. chat.atAll = true;
  202. }
  203. }
  204. // 间隔大于10分钟插入时间显示
  205. if (!chat.lastTimeTip || (chat.lastTimeTip < msgInfo.sendTime - 600 * 1000)) {
  206. chat.messages.push({
  207. sendTime: msgInfo.sendTime,
  208. type: MESSAGE_TYPE.TIP_TIME,
  209. });
  210. chat.lastTimeTip = msgInfo.sendTime;
  211. }
  212. // 根据id顺序插入,防止消息乱序
  213. let insertPos = chat.messages.length;
  214. // 防止 图片、文件 在发送方 显示 在顶端 因为还没存库,id=0
  215. if (msgInfo.id && msgInfo.id > 0) {
  216. for (let idx in chat.messages) {
  217. if (chat.messages[idx].id && msgInfo.id < chat.messages[idx].id) {
  218. insertPos = idx;
  219. console.log(`消息出现乱序,位置:${chat.messages.length},修正至:${insertPos}`);
  220. break;
  221. }
  222. }
  223. }
  224. if (insertPos == chat.messages.length) {
  225. // 这种赋值效率最高
  226. chat.messages[insertPos] = msgInfo;
  227. } else {
  228. chat.messages.splice(insertPos, 0, msgInfo);
  229. }
  230. chat.stored = false;
  231. this.saveToStorage();
  232. },
  233. updateMessage(msgInfo, chatInfo) {
  234. // 获取对方id或群id
  235. let chat = this.findChat(chatInfo);
  236. let message = this.findMessage(chat, msgInfo);
  237. if (message) {
  238. // 属性拷贝
  239. Object.assign(message, msgInfo);
  240. chat.stored = false;
  241. this.saveToStorage();
  242. }
  243. },
  244. deleteMessage(msgInfo, chatInfo) {
  245. // 获取对方id或群id
  246. let chat = this.findChat(chatInfo);
  247. let isColdMessage = false;
  248. for (let idx in chat.messages) {
  249. // 已经发送成功的,根据id删除
  250. if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
  251. chat.messages.splice(idx, 1);
  252. isColdMessage = idx < chat.hotMinIdx;
  253. break;
  254. }
  255. // 正在发送中的消息可能没有id,只有临时id
  256. if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) {
  257. chat.messages.splice(idx, 1);
  258. isColdMessage = idx < chat.hotMinIdx;
  259. break;
  260. }
  261. }
  262. chat.stored = false;
  263. this.saveToStorage(isColdMessage);
  264. },
  265. recallMessage(msgInfo, chatInfo) {
  266. let chat = this.findChat(chatInfo);
  267. if (!chat) return;
  268. let isColdMessage = false;
  269. // 要撤回的消息id
  270. let id = msgInfo.content;
  271. let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName;
  272. for (let idx in chat.messages) {
  273. let m = chat.messages[idx];
  274. if (m.id && m.id == id) {
  275. // 改造成一条提示消息
  276. m.status = MESSAGE_STATUS.RECALL;
  277. m.content = name + "撤回了一条消息";
  278. m.type = MESSAGE_TYPE.TIP_TEXT
  279. // 会话列表
  280. chat.lastContent = m.content;
  281. chat.lastSendTime = msgInfo.sendTime;
  282. chat.sendNickName = '';
  283. if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) {
  284. chat.unreadCount++;
  285. }
  286. isColdMessage = idx < chat.hotMinIdx;
  287. }
  288. // 被引用的消息也要撤回
  289. if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) {
  290. m.quoteMessage.content = "引用内容已撤回";
  291. m.quoteMessage.status = MESSAGE_STATUS.RECALL;
  292. m.quoteMessage.type = MESSAGE_TYPE.TIP_TEXT
  293. }
  294. }
  295. chat.stored = false;
  296. this.saveToStorage(isColdMessage);
  297. },
  298. updateChatFromFriend(friend) {
  299. let chat = this.findChatByFriend(friend.id)
  300. if (chat && (chat.headImage != friend.headImage ||
  301. chat.showName != friend.nickName)) {
  302. // 更新会话中的群名和头像
  303. chat.headImage = friend.headImage;
  304. chat.showName = friend.nickName;
  305. chat.stored = false;
  306. this.saveToStorage();
  307. }
  308. },
  309. updateChatFromUser(user) {
  310. let chat = this.findChatByFriend(user.id);
  311. // 更新会话中的昵称和头像
  312. if (chat && (chat.headImage != user.headImageThumb ||
  313. chat.showName != user.nickName)) {
  314. chat.headImage = user.headImageThumb;
  315. chat.showName = user.nickName;
  316. chat.stored = false;
  317. this.saveToStorage();
  318. }
  319. },
  320. updateChatFromGroup(group) {
  321. let chat = this.findChatByGroup(group.id);
  322. if (chat && (chat.headImage != group.headImageThumb ||
  323. chat.showName != group.showGroupName)) {
  324. // 更新会话中的群名称和头像
  325. chat.headImage = group.headImageThumb;
  326. chat.showName = group.showGroupName;
  327. chat.stored = false;
  328. this.saveToStorage();
  329. }
  330. },
  331. setLoadingPrivateMsg(loading) {
  332. this.loadingPrivateMsg = loading;
  333. if (!this.isLoading()) {
  334. this.refreshChats()
  335. }
  336. },
  337. setLoadingGroupMsg(loading) {
  338. this.loadingGroupMsg = loading;
  339. if (!this.isLoading()) {
  340. this.refreshChats()
  341. }
  342. },
  343. refreshChats() {
  344. if (!cacheChats) return;
  345. // 排序
  346. cacheChats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime);
  347. // 记录热数据索引位置
  348. cacheChats.forEach(chat => chat.hotMinIdx = chat.messages.length);
  349. // 将消息一次性装载回来
  350. this.chats = cacheChats;
  351. // 清空缓存,不再使用
  352. cacheChats = null;
  353. // 消息持久化
  354. this.saveToStorage(true);
  355. },
  356. saveToStorage(withColdMessage) {
  357. // 加载中不保存,防止卡顿
  358. if (this.isLoading()) {
  359. return;
  360. }
  361. const userStore = useUserStore();
  362. let userId = userStore.userInfo.id;
  363. let key = "chats-app-" + userId;
  364. let chatKeys = [];
  365. // 按会话为单位存储,只存储有改动的会话
  366. this.chats.forEach((chat) => {
  367. let chatKey = `${key}-${chat.type}-${chat.targetId}`
  368. if (!chat.stored) {
  369. chat.stored = true;
  370. if (chat.delete) {
  371. uni.removeStorageSync(chatKey);
  372. } else {
  373. // 存储冷数据
  374. if (withColdMessage) {
  375. let coldChat = Object.assign({}, chat);
  376. coldChat.messages = chat.messages.slice(0, chat.hotMinIdx);
  377. uni.setStorageSync(chatKey, coldChat)
  378. }
  379. // 存储热消息
  380. let hotKey = chatKey + '-hot';
  381. if (chat.messages.length > chat.hotMinIdx) {
  382. let hotChat = Object.assign({}, chat);
  383. hotChat.messages = chat.messages.slice(chat.hotMinIdx)
  384. uni.setStorageSync(hotKey, hotChat);
  385. console.log("热数据:",hotChat.messages.length)
  386. } else {
  387. uni.removeStorageSync(hotKey);
  388. }
  389. }
  390. }
  391. if (!chat.delete) {
  392. chatKeys.push(chatKey);
  393. }
  394. })
  395. // 会话核心信息
  396. let chatsData = {
  397. privateMsgMaxId: this.privateMsgMaxId,
  398. groupMsgMaxId: this.groupMsgMaxId,
  399. chatKeys: chatKeys
  400. }
  401. uni.setStorageSync(key, chatsData)
  402. // 清理已删除的会话
  403. this.chats = this.chats.filter(chat => !chat.delete)
  404. },
  405. clear(state) {
  406. cacheChats = [];
  407. this.chats = [];
  408. this.privateMsgMaxId = 0;
  409. this.groupMsgMaxId = 0;
  410. this.loadingPrivateMsg = false;
  411. this.loadingGroupMsg = false;
  412. },
  413. loadChat() {
  414. return new Promise((resolve, reject) => {
  415. let userStore = useUserStore();
  416. let userId = userStore.userInfo.id;
  417. let chatsData = uni.getStorageSync("chats-app-" + userId)
  418. if (chatsData) {
  419. if (chatsData.chatKeys) {
  420. chatsData.chats = [];
  421. chatsData.chatKeys.forEach(key => {
  422. let coldChat = uni.getStorageSync(key);
  423. let hotChat = uni.getStorageSync(key + '-hot');
  424. if (!coldChat && hotChat) {
  425. return;
  426. }
  427. // 冷热消息合并
  428. let chat = Object.assign({}, coldChat, hotChat);
  429. if (hotChat && coldChat) {
  430. chat.messages = coldChat.messages.concat(hotChat.messages)
  431. }
  432. chatsData.chats.push(chat);
  433. })
  434. }
  435. this.initChats(chatsData);
  436. }
  437. resolve()
  438. })
  439. }
  440. },
  441. getters: {
  442. isLoading: (state) => () => {
  443. return state.loadingPrivateMsg || state.loadingGroupMsg
  444. },
  445. curChats: (state) => {
  446. if (cacheChats && state.isLoading()) {
  447. return cacheChats;
  448. }
  449. return state.chats;
  450. },
  451. findChatIdx: (state) => (chat) => {
  452. let chats = state.curChats;
  453. for (let idx in chats) {
  454. if (chats[idx].type == chat.type &&
  455. chats[idx].targetId === chat.targetId) {
  456. chat = state.chats[idx];
  457. return idx;
  458. }
  459. }
  460. },
  461. findChat: (state) => (chat) => {
  462. let chats = state.curChats;
  463. let idx = state.findChatIdx(chat);
  464. return chats[idx];
  465. },
  466. findChatByFriend: (state) => (fid) => {
  467. return state.curChats.find(chat => chat.type == 'PRIVATE' &&
  468. chat.targetId == fid)
  469. },
  470. findChatByGroup: (state) => (gid) => {
  471. return state.curChats.find(chat => chat.type == 'GROUP' &&
  472. chat.targetId == gid)
  473. },
  474. findMessage: (state) => (chat, msgInfo) => {
  475. if (!chat) {
  476. return null;
  477. }
  478. for (let idx in chat.messages) {
  479. // 通过id判断
  480. if (msgInfo.id && chat.messages[idx].id == msgInfo.id) {
  481. return chat.messages[idx];
  482. }
  483. // 正在发送中的消息可能没有id,只有tmpId
  484. if (msgInfo.tmpId && chat.messages[idx].tmpId &&
  485. chat.messages[idx].tmpId == msgInfo.tmpId) {
  486. return chat.messages[idx];
  487. }
  488. }
  489. }
  490. }
  491. });