conversation.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. import { emConversation, emSilent } from '@/EaseIM/emApis';
  2. import { EMClient } from '@/EaseIM';
  3. import { CHAT_TYPE } from '@/EaseIM/constant';
  4. import Vue from 'vue';
  5. import MessageStore from './message';
  6. const {
  7. fetchPinConversationFromServer,
  8. pinConversationItem,
  9. fetchConversationFromServer,
  10. removeConversationFromServer,
  11. sendChannelAck,
  12. } = emConversation();
  13. const {
  14. getSilentModeForConversation,
  15. getSilentModeForConversationList,
  16. setSilentModeForConversation,
  17. clearRemindTypeForConversation,
  18. } = emSilent();
  19. const ConversationStore = {
  20. state: {
  21. chattingId: '', //进入聊天页面聊天中的目标聊天用户信息
  22. chattingChatType: CHAT_TYPE.SINGLE_CHAT, //当前聊天页面中的聊天类型类型
  23. chattingTypingStatus: false, //当前聊天页面中是否正在输入
  24. pinConversationList: [],
  25. conversationList: [],
  26. silentConversationMap: {},
  27. conversationName:'',
  28. conversationUrl:'',
  29. //进入聊天页面聊天中的目标聊天用户昵称
  30. //进入聊天页面聊天中的目标聊天用户头像
  31. },
  32. mutations: {
  33. RESET_CONVERSATION_STORE: (state) => {
  34. state.chattingId = '';
  35. state.chattingChatType = CHAT_TYPE.SINGLE_CHAT;
  36. state.chattingTypingStatus = false;
  37. state.pinConversationList = [];
  38. state.conversationList = [];
  39. state.silentConversationMap = {};
  40. state.conversationName='';
  41. state.conversationUrl='';
  42. },
  43. /**
  44. * Sets the chatting user info of the current page.
  45. * @param {object} payload - The payload contains the target user id and chat type.
  46. * @param {string} payload.targetId - The target user id.
  47. * @param {CHAT_TYPE} payload.chatType - The chat type.
  48. */
  49. /**
  50. * Sets the chatting user info of the current page.
  51. * @param {object} payload - The payload contains the target user id and chat type.
  52. * @param {string} payload.targetId - The target user id.
  53. * @param {CHAT_TYPE} payload.chatType - The chat type.
  54. */
  55. SET_CHATING_USER_INFO: (state, payload) => {
  56. state.chattingId = payload.targetId || '';
  57. state.chattingChatType = payload.chatType || CHAT_TYPE.SINGLE_CHAT;
  58. console.log('payload------',payload);
  59. state.conversationName='';
  60. },
  61. /**
  62. * Sets the typing status of the current chatting user.
  63. * @param {boolean} payload - The typing status.
  64. */
  65. SET_CHATING_USER_INFO_TYPING_STATUS: (state, payload) => {
  66. state.chattingTypingStatus = payload;
  67. },
  68. /**
  69. * Sets the pin conversation list of the current page.
  70. * @param {object} state - The state object.
  71. * @param {array} pinConversationList - The pin conversation list.
  72. */
  73. SET_PIN_CONVERSATION_LIST: (state, pinConversationList) => {
  74. state.pinConversationList = [...pinConversationList];
  75. },
  76. /**
  77. * Sets the silent conversation map of the current page.
  78. * @param {object} state - The state object.
  79. * @param {string} type - The type of the action.
  80. * @param {object} data - The data contains the conversation id and type.
  81. */
  82. SET_SILENT_CONVERSATION_MAP: (state, payload) => {
  83. const { type, data } = payload;
  84. if (type === 'init') {
  85. state.silentConversationMap = data;
  86. }
  87. if (type === 'setSingleSilentMode') {
  88. const { conversationId, type } = data;
  89. if (!state.silentConversationMap[conversationId]) {
  90. Vue.set(state.silentConversationMap, conversationId, {});
  91. }
  92. state.silentConversationMap[conversationId] = { type };
  93. }
  94. },
  95. UPDATE_PIN_CONVERSATION_ITEM: (state, conversationItem) => {
  96. const { conversationId, isPinned } = conversationItem;
  97. const pinConversationItemIndex = state.pinConversationList.findIndex(
  98. (item) => item.conversationId === conversationId
  99. );
  100. const unPinConversationItemIndex = state.conversationList.findIndex(
  101. (item) => item.conversationId === conversationId
  102. );
  103. console.log('unPinConversationItemIndex', unPinConversationItemIndex);
  104. if (isPinned) {
  105. state.pinConversationList.unshift(conversationItem);
  106. unPinConversationItemIndex > -1 &&
  107. state.conversationList.splice(unPinConversationItemIndex, 1);
  108. } else {
  109. state.conversationList.unshift(conversationItem);
  110. pinConversationItemIndex > -1 &&
  111. state.pinConversationList.splice(pinConversationItemIndex, 1);
  112. }
  113. },
  114. SET_CONVERSATION_LIST: (state, conversationList) => {
  115. state.conversationList = [...conversationList];
  116. },
  117. DELETE_CONVERSATION_ITEM: (state, conversationId) => {
  118. if (state.pinConversationList.length) {
  119. state.pinConversationList = state.pinConversationList.filter(
  120. (item) => item.conversationId !== conversationId
  121. );
  122. }
  123. if (state.conversationList.length) {
  124. state.conversationList = state.conversationList.filter(
  125. (item) => item.conversationId !== conversationId
  126. );
  127. }
  128. },
  129. UPDATE_CONVERSATION_ITEM: (state, payload) => {
  130. console.log('>>>>更新会话列表', payload);
  131. const { conversationId, lastMessage } = payload;
  132. let foundChannel = false;
  133. const updateConversationItem = (conversationItem) => {
  134. if (
  135. lastMessage.from !== EMClient.user &&
  136. state.chattingId !== conversationId
  137. ) {
  138. conversationItem.unReadCount += 1;
  139. }
  140. conversationItem.lastMessage = { ...lastMessage };
  141. foundChannel = true;
  142. };
  143. state.conversationList.forEach((conversationItem) => {
  144. if (conversationItem.conversationId === conversationId) {
  145. updateConversationItem(conversationItem);
  146. }
  147. });
  148. state.pinConversationList.forEach((conversationItem) => {
  149. if (conversationItem.conversationId === conversationId) {
  150. updateConversationItem(conversationItem);
  151. }
  152. });
  153. if (!foundChannel) {
  154. console.log('>>>新增会话列表');
  155. const conversationItem = {
  156. conversationId,
  157. conversationType: lastMessage.chatType,
  158. lastMessage,
  159. pinnedTime: 0,
  160. isPinned: false,
  161. unReadCount: 1,
  162. conversationName:'',//会话的名称
  163. conversationUrl:'',//会话头像
  164. };
  165. console.log('conversationItem', conversationItem);
  166. state.conversationList.push({
  167. ...conversationItem,
  168. });
  169. }
  170. },
  171. clearConversationUnReadNum(state, payload) {
  172. const { conversationId } = payload;
  173. state.conversationList.forEach((conversationItem) => {
  174. if (conversationItem.conversationId === conversationId) {
  175. conversationItem.unReadCount = 0;
  176. }
  177. });
  178. },
  179. SET_CONVERSATION_ITEM_READ_SATUS: (state, payload) => {
  180. const {
  181. conversationItem: { isPinned, conversationId },
  182. isRead,
  183. } = payload;
  184. const conversationList = isPinned
  185. ? state.pinConversationList
  186. : state.conversationList;
  187. const targetConversationItem = conversationList.find(
  188. (conversationItem) => conversationItem.conversationId === conversationId
  189. );
  190. if (targetConversationItem) {
  191. if (isRead) {
  192. targetConversationItem.unReadCount = 0;
  193. }
  194. targetConversationItem.isRead = isRead;
  195. }
  196. },
  197. },
  198. actions: {
  199. //主动更新lastMessage
  200. updateConversationLastMsg: async ({ commit, dispatch }, payload) => {
  201. const { conversationId } = payload;
  202. const { messageCollection } = MessageStore.state;
  203. //收集conversationId 对应的消息合集。
  204. if (messageCollection[conversationId]) {
  205. const messagesList = messageCollection[conversationId];
  206. const lastMessage = messagesList[0];
  207. console.log('>>>>>>执行主动更新对应会话的最后一条数据。', lastMessage);
  208. commit('UPDATE_CONVERSATION_ITEM', {
  209. conversationId,
  210. lastMessage,
  211. });
  212. }
  213. console.log('messageCollection', messageCollection);
  214. },
  215. fetchPinConversationList: async ({ commit }) => {
  216. try {
  217. const result = await fetchPinConversationFromServer();
  218. console.log('>>>>>>>置顶会话result', result);
  219. commit('SET_PIN_CONVERSATION_LIST', result.data.conversations);
  220. } catch (error) {
  221. console.log('>>>>>置顶会话列表拉取失败', error);
  222. }
  223. },
  224. fetchConversationList: async ({ commit, dispatch }) => {
  225. let filteredConversationList = [];
  226. try {
  227. const result = await fetchConversationFromServer();
  228. console.log('>>>>>>>result', result);
  229. filteredConversationList = result.filter(
  230. (item) => item.isPinned === false
  231. );
  232. commit('SET_CONVERSATION_LIST', [...filteredConversationList]);
  233. dispatch('fetchSilentConversationList', [...result]);
  234. } catch (error) {
  235. console.log('>>>>> 会话列表拉取失败', error);
  236. }
  237. },
  238. //处理会话置顶
  239. pinConversationItem: async ({ commit }, params) => {
  240. const { conversationId, conversationType, isPinned } = params;
  241. try {
  242. const result = await pinConversationItem({
  243. conversationId,
  244. conversationType,
  245. isPinned,
  246. });
  247. commit('UPDATE_PIN_CONVERSATION_ITEM', { ...params });
  248. console.log('>>>>>>>置顶会话成功', result);
  249. } catch (error) {
  250. console.log('>>>>>置顶会话列表拉取失败', error);
  251. }
  252. },
  253. deleteConversation: async ({ commit }, params) => {
  254. const { conversationId, conversationType } = params;
  255. return new Promise((resolve, reject) => {
  256. removeConversationFromServer(conversationId, conversationType)
  257. .then((res) => {
  258. commit('DELETE_CONVERSATION_ITEM', conversationId);
  259. resolve(res);
  260. })
  261. .catch((err) => {
  262. console.log('>>>>会话列表删除失败', error);
  263. reject(err);
  264. });
  265. });
  266. },
  267. sendConversatonReadedAck: async ({ commit }, params) => {
  268. const { targetId, chatType } = params;
  269. sendChannelAck(targetId, chatType);
  270. commit('clearConversationUnReadNum', { conversationId: targetId });
  271. },
  272. //获取会话免打扰状态
  273. fetchSilentConversationList: async ({ commit }, params) => {
  274. const conversationList = params;
  275. const silentConversationListParams = conversationList.map(
  276. (conversation) => {
  277. return {
  278. id: conversation.conversationId,
  279. type: conversation.conversationType,
  280. };
  281. }
  282. );
  283. try {
  284. const { data } = await getSilentModeForConversationList(
  285. silentConversationListParams
  286. );
  287. const silentUserInfo = { ...data?.user, ...data?.group };
  288. commit('SET_SILENT_CONVERSATION_MAP', {
  289. type: 'init',
  290. data: silentUserInfo,
  291. });
  292. } catch (error) {
  293. console.log('>>>>>会话免打扰列表拉取失败', error);
  294. }
  295. },
  296. //获取单个会话免打扰状态
  297. fetchSilentConversation: ({ commit }, params) => {
  298. const { conversationId, chatType } = params;
  299. return new Promise((resolve, reject) => {
  300. getSilentModeForConversation(conversationId, chatType)
  301. .then((res) => {
  302. if (Object.keys(res?.data).length) {
  303. commit('SET_SILENT_CONVERSATION_MAP', {
  304. type: 'setSingleSilentMode',
  305. data: {
  306. conversationId,
  307. type: 'NONE',
  308. },
  309. });
  310. } else {
  311. commit('SET_SILENT_CONVERSATION_MAP', {
  312. type: 'setSingleSilentMode',
  313. data: {
  314. conversationId,
  315. type: '',
  316. },
  317. });
  318. }
  319. resolve(res?.data);
  320. })
  321. .catch((error) => {
  322. reject(error);
  323. });
  324. });
  325. },
  326. //设置会话免打扰
  327. setConversationSilentMode: async ({ commit }, params) => {
  328. const { conversationId, type } = params;
  329. try {
  330. if (params.hasOwnProperty('options')) {
  331. console.log('>>>>设置会话免打扰');
  332. await setSilentModeForConversation({ ...params });
  333. commit('SET_SILENT_CONVERSATION_MAP', {
  334. type: 'setSingleSilentMode',
  335. data: {
  336. conversationId,
  337. type: 'NONE',
  338. },
  339. });
  340. } else {
  341. console.log('>>>>>取消会话免打扰');
  342. await clearRemindTypeForConversation({ ...params });
  343. commit('SET_SILENT_CONVERSATION_MAP', {
  344. type: 'setSingleSilentMode',
  345. data: {
  346. conversationId,
  347. type: '',
  348. },
  349. });
  350. }
  351. } catch (error) {
  352. console.log('>>>>>>会话设置失败', error);
  353. }
  354. },
  355. //调整会话已读状态
  356. setConversationReadStatus: async ({ commit }, params) => {
  357. const { conversationItem, isRead } = params;
  358. if (isRead) {
  359. sendChannelAck(
  360. conversationItem.conversationId,
  361. conversationItem.conversationType
  362. );
  363. commit('SET_CONVERSATION_ITEM_READ_SATUS', {
  364. conversationItem,
  365. isRead: true,
  366. });
  367. } else {
  368. commit('SET_CONVERSATION_ITEM_READ_SATUS', {
  369. conversationItem,
  370. isRead: false,
  371. });
  372. }
  373. },
  374. },
  375. getters: {
  376. //排序会话列表
  377. sortedConversationList(state) {
  378. return state.conversationList.sort((a, b) => {
  379. return b.lastMessage.time - a.lastMessage.time;
  380. });
  381. },
  382. //排序指定会话列表
  383. sortedPinConversationList(state) {
  384. return state.pinConversationList.sort((a, b) => {
  385. return b.lastMessage.time - a.lastMessage.time;
  386. });
  387. },
  388. //会话免打扰信息
  389. silentConversationMap(state) {
  390. return state.silentConversationMap;
  391. },
  392. //会话未读总数
  393. calcAllUnReadNumFromConversation(state) {
  394. const pinConversationListUnReadNum = state.pinConversationList.reduce(
  395. (a, c) => {
  396. if (
  397. state.silentConversationMap[c.conversationId] &&
  398. state.silentConversationMap[c.conversationId]?.type !== 'NONE' &&
  399. c.unReadCount
  400. ) {
  401. return a + c.unReadCount;
  402. } else {
  403. return a;
  404. }
  405. },
  406. 0
  407. );
  408. const conversationListUnReadNum = state.conversationList.reduce(
  409. (a, c) => {
  410. if (
  411. state.silentConversationMap[c.conversationId] &&
  412. state.silentConversationMap[c.conversationId]?.type !== 'NONE' &&
  413. c.unReadCount
  414. ) {
  415. return a + c.unReadCount;
  416. } else {
  417. return a;
  418. }
  419. },
  420. 0
  421. );
  422. return pinConversationListUnReadNum + conversationListUnReadNum;
  423. },
  424. //聊天中用户ID
  425. chattingId(state) {
  426. return state.chattingId;
  427. },
  428. chattingChatType(state) {
  429. return state.chattingChatType;
  430. },
  431. chattingTypingStatus(state) {
  432. return state.chattingTypingStatus;
  433. },
  434. },
  435. };
  436. export default ConversationStore;