webSocketStore.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. // src/stores/websocket.js
  2. import { defineStore } from "pinia";
  3. import { $root as protobuf } from "@/common/proto/proto";
  4. import * as Constant from "@/common/constant/Constant";
  5. import { useWalletStore } from "@/stores/modules/walletStore";
  6. import { getMessageApi, friendRequest, groupList } from "@/api/path/im.api";
  7. import { showDialog } from 'vant';
  8. import { eventBus } from '@/utils/utils';
  9. import { useSystemStore } from "@/stores/modules/systemStore";
  10. import * as MsgType from "@/common/constant/msgType";
  11. import {
  12. setMessageHook,
  13. handleMessageHook,
  14. } from "@/views/im/hook/messagesHook";
  15. // 配置常量
  16. const WS_CONFIG = {
  17. HEARTBEAT_INTERVAL: 30000, // 30秒
  18. HEARTBEAT_TIMEOUT: 10000, // 10秒
  19. HEARTBEAT_RETRY_LIMIT: 3,
  20. RECONNECT_BASE_INTERVAL: 1000,
  21. RECONNECT_MAX_INTERVAL: 30000,
  22. RECONNECT_MAX_ATTEMPTS: Infinity,
  23. RECONNECT_MULTIPLIER: 1.5,
  24. MESSAGE_QUEUE_MAX_SIZE: 100,
  25. MESSAGE_QUEUE_FLUSH_INTERVAL: 5000,
  26. };
  27. const messageList = {};//消息缓存
  28. export const useWebSocketStore = defineStore("webSocketStore", {
  29. state: () => ({
  30. socket: null,
  31. peer: null,
  32. connectionState: "disconnected", // 'connecting', 'connected', 'disconnecting', 'error'
  33. reconnectAttempts: 0,
  34. sessionId:null,//当前会话id
  35. messages: [],
  36. groupMembersList:{},//群成员列表
  37. toUserInfo: {},
  38. unreadMessages: [],
  39. uuid: null,
  40. onMessageCallbacks: [],
  41. messageQueue: [],
  42. lastActivityTime: 0,
  43. stats: {
  44. sentMessages: 0,
  45. receivedMessages: 0,
  46. failedMessages: 0,
  47. reconnects: 0,
  48. },
  49. heartbeat: {
  50. timer: null,
  51. timeout: null,
  52. retryCount: 0,
  53. },
  54. reconnect: {
  55. timer: null,
  56. currentAttempt: 0,
  57. },
  58. queueFlushTimer: null,
  59. loading:false,
  60. applyfriend:{},//好友申请数据
  61. unread:false,//判断有无好友申请
  62. chatDelAuth:{},//控制会话权限
  63. chatRefresh:0,//刷新会话列表
  64. indexs:0,// 接收消息计数器
  65. needRefreshIm:0,//刷新会话
  66. }),
  67. persist: {
  68. key: "toUserInfo",
  69. storage: localStorage,
  70. paths: ["toUserInfo", "uuid"],
  71. serializer: {
  72. serialize: (state) =>
  73. JSON.stringify({
  74. toUserInfo: state.toUserInfo,
  75. uuid: state.uuid,
  76. }),
  77. deserialize: (str) => {
  78. const data = JSON.parse(str);
  79. return {
  80. toUserInfo: data.toUserInfo || {},
  81. uuid: data.uuid || null,
  82. };
  83. },
  84. },
  85. },
  86. getters: {
  87. isConnected(state) {
  88. return state.connectionState === "connected";
  89. },
  90. hasUnreadMessages(state) {
  91. return state.unreadMessages.length > 0;
  92. },
  93. connectionStatus(state) {
  94. return state.connectionState;
  95. },
  96. },
  97. actions: {
  98. // 初始化连接
  99. connect(userUuid, callback) {
  100. if (!userUuid) {
  101. console.error("连接失败: 缺少 userUuid");
  102. return;
  103. }
  104. // 如果正在连接或已连接,则先断开
  105. if (
  106. this.connectionState === "connected" ||
  107. this.connectionState === "connecting"
  108. ) {
  109. this.disconnect();
  110. }
  111. this.uuid = userUuid;
  112. this.connectionState = "connecting";
  113. this.stats.reconnects++;
  114. try {
  115. const wsUrl = `${import.meta.env.VITE_PRO_IM_WSS}?user=${userUuid}`;
  116. this.socket = new WebSocket(wsUrl);
  117. this.socket.onopen = () => {
  118. this.connectionState = "connected";
  119. this.reconnect.currentAttempt = 0;
  120. this.lastActivityTime = Date.now();
  121. this.startHeartbeat();
  122. this.startQueueFlush();
  123. if (callback && typeof callback === "function") {
  124. callback();
  125. }
  126. console.log("WebSocket 连接成功");
  127. this.flushMessageQueue(); // 连接成功后立即发送队列中的消息
  128. };
  129. this.socket.onmessage = (event) => {
  130. this.lastActivityTime = Date.now();
  131. this.handleMessage(event.data);
  132. };
  133. this.socket.onclose = () => {
  134. this.connectionState = "disconnected";
  135. this.cleanupTimers();
  136. if (
  137. this.reconnect.currentAttempt < WS_CONFIG.RECONNECT_MAX_ATTEMPTS
  138. ) {
  139. this.scheduleReconnect();
  140. }
  141. };
  142. this.socket.onerror = (error) => {
  143. this.connectionState = "error";
  144. console.error("WebSocket 错误:", error);
  145. this.cleanupTimers();
  146. this.scheduleReconnect();
  147. };
  148. } catch (error) {
  149. console.error("创建 WebSocket 失败:", error);
  150. this.connectionState = "error";
  151. this.scheduleReconnect();
  152. }
  153. },
  154. // 断开连接
  155. disconnect() {
  156. this.connectionState = "disconnecting";
  157. this.cleanupTimers();
  158. if (this.socket) {
  159. try {
  160. this.socket.close();
  161. } catch (e) {
  162. console.error("关闭 WebSocket 时出错:", e);
  163. }
  164. this.socket = null;
  165. }
  166. if (this.peer) {
  167. this.peer.close();
  168. this.peer = null;
  169. }
  170. this.connectionState = "disconnected";
  171. },
  172. // 清理所有定时器
  173. cleanupTimers() {
  174. if (this.heartbeat.timer) clearTimeout(this.heartbeat.timer);
  175. if (this.heartbeat.timeout) clearTimeout(this.heartbeat.timeout);
  176. if (this.reconnect.timer) clearTimeout(this.reconnect.timer);
  177. if (this.queueFlushTimer) clearInterval(this.queueFlushTimer);
  178. this.heartbeat.timer = null;
  179. this.heartbeat.timeout = null;
  180. this.reconnect.timer = null;
  181. this.queueFlushTimer = null;
  182. this.heartbeat.retryCount = 0;
  183. },
  184. // 启动心跳检测
  185. startHeartbeat() {
  186. this.cleanupHeartbeat();
  187. this.heartbeat.timer = setTimeout(() => {
  188. if (this.isConnected) {
  189. try {
  190. const pingMsg = {
  191. type: "heatbeat",
  192. content: "ping",
  193. timestamp: Date.now(),
  194. };
  195. this.sendRawMessage(pingMsg);
  196. // 设置响应超时检测
  197. this.heartbeat.timeout = setTimeout(() => {
  198. this.heartbeat.retryCount++;
  199. if (
  200. this.heartbeat.retryCount >= WS_CONFIG.HEARTBEAT_RETRY_LIMIT
  201. ) {
  202. console.error("心跳响应超时,关闭连接");
  203. this.disconnect();
  204. } else {
  205. console.warn(
  206. `心跳无响应,第${this.heartbeat.retryCount}次重试`
  207. );
  208. this.startHeartbeat(); // 重新发送心跳
  209. }
  210. }, WS_CONFIG.HEARTBEAT_TIMEOUT);
  211. } catch (error) {
  212. console.error("心跳发送失败:", error);
  213. this.scheduleReconnect();
  214. }
  215. }
  216. }, WS_CONFIG.HEARTBEAT_INTERVAL);
  217. },
  218. // 清理心跳定时器
  219. cleanupHeartbeat() {
  220. if (this.heartbeat.timer) clearTimeout(this.heartbeat.timer);
  221. if (this.heartbeat.timeout) clearTimeout(this.heartbeat.timeout);
  222. this.heartbeat.timer = null;
  223. this.heartbeat.timeout = null;
  224. },
  225. // 安排重连
  226. scheduleReconnect() {
  227. if (this.reconnect.timer) return;
  228. this.reconnect.currentAttempt++;
  229. // 指数退避算法计算重连间隔
  230. const delay = Math.min(
  231. WS_CONFIG.RECONNECT_BASE_INTERVAL *
  232. Math.pow(
  233. WS_CONFIG.RECONNECT_MULTIPLIER,
  234. this.reconnect.currentAttempt - 1
  235. ),
  236. WS_CONFIG.RECONNECT_MAX_INTERVAL
  237. );
  238. console.log(
  239. `将在 ${delay}ms 后尝试第 ${this.reconnect.currentAttempt} 次重连`
  240. );
  241. this.reconnect.timer = setTimeout(() => {
  242. this.reconnect.timer = null;
  243. if (!this.isConnected && this.uuid) {
  244. this.connect(this.uuid);
  245. }
  246. }, delay);
  247. },
  248. // 发送原始消息(不经过队列)
  249. sendRawMessage(messageData) {
  250. if (!this.isConnected) {
  251. throw new Error("WebSocket 未连接");
  252. }
  253. try {
  254. const MessageType = protobuf.lookupType("protocol.Message");
  255. const messagePB = MessageType.create(messageData);
  256. const buffer = MessageType.encode(messagePB).finish();
  257. this.socket.send(buffer);
  258. this.stats.sentMessages++;
  259. return true;
  260. } catch (error) {
  261. console.error("消息编码错误:", error);
  262. this.stats.failedMessages++;
  263. return false;
  264. }
  265. },
  266. // 发送消息(自动排队)
  267. sendMessage(messageData) {
  268. const walletStore = useWalletStore();
  269. // 构造完整消息
  270. const fullMessage = {
  271. to: this.toUserInfo.uuid,
  272. from: walletStore.account,
  273. ...messageData,
  274. fromUsername: walletStore.username,
  275. avatar: walletStore.avatar,
  276. timestamp: Date.now(),
  277. };
  278. // 如果连接正常,直接发送
  279. if (this.isConnected) {
  280. const success = this.sendRawMessage(fullMessage);
  281. if (success) {
  282. setMessageHook(fullMessage, this);
  283. return true;
  284. }
  285. }
  286. // 如果发送失败或未连接,加入队列
  287. if (this.messageQueue.length < WS_CONFIG.MESSAGE_QUEUE_MAX_SIZE) {
  288. this.messageQueue.push(fullMessage);
  289. console.log("消息已加入队列,等待发送");
  290. return true;
  291. } else {
  292. console.error("消息队列已满,丢弃消息");
  293. return false;
  294. }
  295. },
  296. // 启动队列刷新定时器
  297. startQueueFlush() {
  298. if (this.queueFlushTimer) return;
  299. this.queueFlushTimer = setInterval(() => {
  300. this.flushMessageQueue();
  301. }, WS_CONFIG.MESSAGE_QUEUE_FLUSH_INTERVAL);
  302. },
  303. // 发送队列中的所有消息
  304. flushMessageQueue() {
  305. if (!this.isConnected || this.messageQueue.length === 0) return;
  306. while (this.messageQueue.length > 0) {
  307. const message = this.messageQueue.shift();
  308. try {
  309. const success = this.sendRawMessage(message);
  310. if (success) {
  311. setMessageHook(message, this);
  312. } else {
  313. // 发送失败,重新放回队列开头
  314. this.messageQueue.unshift(message);
  315. break;
  316. }
  317. } catch (error) {
  318. console.error("发送队列消息失败:", error);
  319. this.messageQueue.unshift(message);
  320. break;
  321. }
  322. }
  323. },
  324. // 处理接收到的消息
  325. handleMessage(data) {
  326. const MessageType = protobuf.lookupType("protocol.Message");
  327. const reader = new FileReader();
  328. reader.onload = (event) => {
  329. try {
  330. const messagePB = MessageType.decode(
  331. new Uint8Array(event.target.result)
  332. );
  333. const message = MessageType.toObject(messagePB, {
  334. longs: String,
  335. enums: String,
  336. bytes: String,
  337. });
  338. this.stats.receivedMessages++;
  339. this.lastActivityTime = Date.now();
  340. handleMessageHook(message, this);
  341. // 调用所有回调函数
  342. this.onMessageCallbacks.forEach((cb) => {
  343. try {
  344. cb(message);
  345. } catch (e) {
  346. console.error("消息回调错误:", e);
  347. }
  348. });
  349. if (message.type === "heatbeat") {
  350. this.heartbeat.retryCount = 0; // 重置心跳重试计数
  351. return;
  352. }
  353. } catch (error) {
  354. console.error("消息解码错误:", error);
  355. this.stats.failedMessages++;
  356. }
  357. };
  358. reader.readAsArrayBuffer(data);
  359. },
  360. // ************功能*************//
  361. // 添加消息回调
  362. addOnMessageCallback(cb) {
  363. if (typeof cb === "function" && !this.onMessageCallbacks.includes(cb)) {
  364. this.onMessageCallbacks.push(cb);
  365. }
  366. },
  367. // 移除消息回调
  368. removeOnMessageCallback(cb) {
  369. this.onMessageCallbacks = this.onMessageCallbacks.filter(
  370. (item) => item !== cb
  371. );
  372. },
  373. // 处理本地消息
  374. pushMessage(message, sessionId = null) {
  375. if(!sessionId){
  376. sessionId = message.from;
  377. }
  378. if (!messageList[sessionId]) {
  379. messageList[sessionId] = [];
  380. }
  381. messageList[sessionId].push(message);
  382. // 检测当前消息
  383. if (this.toUserInfo.uuid === sessionId) {
  384. this.messages.push(message);
  385. this.indexs +=1;
  386. }
  387. // 更新会话最新消息
  388. this.updateSessionNewMessage(message, sessionId)
  389. },
  390. modifyMessageId(message, msg, sessionId = null) {
  391. if(!sessionId){
  392. sessionId = message.from;
  393. }
  394. if (!messageList[sessionId]) {
  395. messageList[sessionId] = [];
  396. }
  397. messageList[sessionId] = messageList[sessionId].map(item => {
  398. if (!item.id && item.msgId + '' === msg?.msgId + '') return {...item, id: msg.id, msgId: undefined};
  399. if (item.id + '' === msg?.msgId + '') return {...item, content: "", url: ""};
  400. return item;
  401. });
  402. // 检测当前消息
  403. if (this.toUserInfo.uuid === sessionId) {
  404. this.messages = this.messages.map(item => {
  405. if (!item.id && item.msgId + '' === message.msgId + '') return {...item, id: msg.id, msgId: undefined};
  406. if (item.id + '' === msg?.msgId + '') return {...item, content: "", url: ""};
  407. return item;
  408. });
  409. }
  410. console.log("修改消息", message, sessionId, messageList, this.messages);
  411. },
  412. modifyMessage(message, msgId, sessionId = null) {
  413. if(!sessionId){
  414. sessionId = message.from;
  415. }
  416. if (!messageList[sessionId]) {
  417. messageList[sessionId] = [];
  418. }
  419. messageList[sessionId] = messageList[sessionId].map(item => {
  420. if (item.id + '' === msgId + '') return {...item, content: "", url: ""};
  421. return item;
  422. });
  423. // 检测当前消息
  424. if (this.toUserInfo.uuid === sessionId) {
  425. this.messages = this.messages.map(item => {
  426. if (item.id + '' === msgId + '') return {...item, content: "", url: ""};
  427. return item;
  428. });
  429. }
  430. },
  431. deleteMessage(message, msgId, sessionId = null) {
  432. if(!sessionId){
  433. sessionId = message.from;
  434. }
  435. if (!messageList[sessionId]) {
  436. messageList[sessionId] = [];
  437. }
  438. console.log("删除消息", message, sessionId, messageList, this.messages);
  439. messageList[sessionId] = messageList[sessionId].filter(item => {
  440. if (item.id + '' === msgId + '') return false;
  441. return true;
  442. });
  443. // 检测当前消息
  444. if (this.toUserInfo.uuid === sessionId) {
  445. this.messages = this.messages.filter(item => {
  446. if (item.id + '' === msgId + '') return false;
  447. return true;
  448. });
  449. }
  450. },
  451. // 获取会话消息
  452. getSessionMessages(sessionId) {
  453. if (!messageList[sessionId]) {
  454. messageList[sessionId] = [];
  455. }
  456. return [...messageList[sessionId]];
  457. },
  458. // 设置当前会话消息
  459. setSessionMessages(sessionId, messages) {
  460. if (!messageList[sessionId]) {
  461. messageList[sessionId] = [];
  462. }
  463. messageList[sessionId] = Array.isArray(messages)?messages:(typeof messages === 'object'?[messages]:[]);
  464. },
  465. // 更换会话
  466. changeSessionMessage(sessionId) {
  467. this.sessionId = sessionId;
  468. this.messages = this.getSessionMessages(sessionId);
  469. },
  470. // 获取历史消息
  471. async getMessages(params) {
  472. const router = useRouter();
  473. const systemStore = useSystemStore();
  474. // if (this.sessionId){
  475. // messageList[this.sessionId] = [...this.messages]
  476. // }
  477. // this.messages = [];
  478. // this.sessionId = this.toUserInfo.uuid //params.uuid;
  479. // if (messageList[this.sessionId]){
  480. // this.messages = messageList[this.sessionId];
  481. // return;
  482. // }
  483. this.sessionId = this.toUserInfo.uuid;
  484. this.messages = this.getSessionMessages(this.sessionId);
  485. if (this.messages.length > 0) {
  486. return;
  487. }
  488. this.loading = true // 开始加载
  489. try {
  490. const res = await getMessageApi({
  491. messageType: params.messageType,
  492. uuid: params.uuid,
  493. friendUsername: params.friendUsername,
  494. });
  495. if(res.code == 200){
  496. // this.messages = (res.data || []).map((item) => {
  497. // item.avatar = item.avatar
  498. // ? `${import.meta.env.VITE_IM_PATH_FIlE}${item.avatar}`
  499. // : item.avatar;
  500. // return item;
  501. // });
  502. this.setSessionMessages(this.sessionId, (res.data || []));
  503. this.changeSessionMessage(this.sessionId);
  504. // return this.messages;
  505. }else{
  506. showDialog({
  507. title: '提示',
  508. message: res.msg,
  509. confirmButtonColor:"#4765dd",
  510. }).then(() => {
  511. systemStore.needRefreshIm = true;
  512. router.back();
  513. });
  514. }
  515. } catch (error) {
  516. console.error("获取消息失败:", error);
  517. throw error;
  518. } finally {
  519. this.loading = false // 结束加载
  520. }
  521. },
  522. // 更新会话列表消息
  523. updateSessionNewMessage(message, sessionId, msg = null) {
  524. const systemStore = useSystemStore();
  525. let index = systemStore.ImsessionList.findIndex(val=> val.uuid == sessionId);
  526. // 已读未读
  527. let unReadNum = 0;
  528. const ts = message.timestamp || Math.floor(Date.now() / 1000);
  529. const time = new Date(ts).toISOString().replace("T", " ").split(".")[0];
  530. // 消息类型映射
  531. const mapSet = {
  532. [MsgType.MSG_TYPE.FILE]: '[文件]',
  533. [MsgType.MSG_TYPE.IMAGE]: '[图片]',
  534. [MsgType.MSG_TYPE.AUDIO]: '[音频]',
  535. [MsgType.MSG_TYPE.VIDEO]: '[视频]',
  536. [MsgType.MSG_TYPE.AUDIO_ONLINE]: '[语音通话]',
  537. [MsgType.MSG_TYPE.VIDEO_ONLINE]: '[视频通话]',
  538. // [Constant.CANCELL_AUDIO_ONLINE]:'[通话结束]',
  539. // [Constant.REJECT_AUDIO_ONLINE]: '[对方拒绝]',
  540. // [Constant.CANCELL_VIDEO_ONLINE]: '[通话结束]',
  541. // [Constant.REJECT_VIDEO_ONLINE]: '[对方拒绝]',
  542. };
  543. // 检测最新消息
  544. let lastMsg = message.contentType === MsgType.MSG_TYPE.TEXT || message.contentType === MsgType.MSG_TYPE.NOTICE ? (msg?msg.content : message.content) : (mapSet[message.contentType] || '[语音视频]');
  545. // 更新
  546. if(index >= 0){
  547. systemStore.ImsessionList = systemStore.ImsessionList.map((item, i)=>{
  548. if(i == index){
  549. item.message = lastMsg;
  550. item.lastTime = time;
  551. item.unReadNum = item.unReadNum + 1;
  552. }
  553. return item;
  554. })
  555. }
  556. },
  557. // 更新缓存里面的会话列表 type:0 发送者 1:接收者
  558. updateSessionList(payload,type = 0,msg) {
  559. const walletStore = useWalletStore();
  560. const message = {...payload};
  561. console.log('缓存中的列表数据', message, msg)
  562. const systemStore = useSystemStore();
  563. const selfUuid = useWalletStore().account; // 当前用户ID
  564. let sessions = systemStore.ImsessionList ? [...systemStore.ImsessionList] : [];
  565. const mapSet = {
  566. [MsgType.MSG_TYPE.FILE]: '[文件]',
  567. [MsgType.MSG_TYPE.IMAGE]: '[图片]',
  568. [MsgType.MSG_TYPE.AUDIO]: '[音频]',
  569. [MsgType.MSG_TYPE.VIDEO]: '[视频]',
  570. [MsgType.MSG_TYPE.AUDIO_ONLINE]: '[语音通话]',
  571. [MsgType.MSG_TYPE.VIDEO_ONLINE]: '[视频通话]',
  572. // [Constant.CANCELL_AUDIO_ONLINE]:'[通话结束]',
  573. // [Constant.REJECT_AUDIO_ONLINE]: '[对方拒绝]',
  574. // [Constant.CANCELL_VIDEO_ONLINE]: '[通话结束]',
  575. // [Constant.REJECT_VIDEO_ONLINE]: '[对方拒绝]',
  576. };
  577. // console.log(sessions, sessions.length)
  578. let lastMsg = message.contentType === MsgType.MSG_TYPE.TEXT || message.contentType === MsgType.MSG_TYPE.NOTICE ? (msg?msg.content : message.content) : (mapSet[message.contentType] || '[语音视频]');
  579. if ([MsgType.MESSAGE_REVOKE, MsgType.MESSAGE_REVOKE_GROUP].includes(message.messageType)){
  580. console.log(211111)
  581. lastMsg = `${message.from == walletStore.account ? '你' : (message.fromUsername || '对方')}撤回了一条消息`
  582. }
  583. let index = -1;
  584. let uuid = type == 0 ? message.to : message.from;
  585. index = sessions.findIndex(s => (s.uuid || s.id) === uuid);
  586. if (message.messageType === 2 && type == 0 && index < 0){
  587. systemStore.needRefreshIm = true;
  588. return;
  589. }
  590. // 过滤无效的消息体
  591. if (!uuid) {
  592. return;
  593. }
  594. // if (message.messageType === 2) {
  595. // // 群聊
  596. // index = sessions.findIndex(s => (s.uuid || s.id) === message.to);
  597. // } else {
  598. // 单聊
  599. // if (message.from === selfUuid) {
  600. // index = sessions.findIndex(s => (s.uuid || s.id) === message.to);
  601. // } else {
  602. // index = sessions.findIndex(s => (s.uuid || s.id) === message.from);
  603. // }
  604. // }
  605. let unReadNum = 0;
  606. const ts = message.timestamp || Math.floor(Date.now() / 1000);
  607. const time = new Date(ts).toISOString().replace("T", " ").split(".")[0];
  608. if (index > -1) {
  609. // 如果退群和踢人需要将用户头像移除
  610. // let avatar = sessions[index].avatar;
  611. // if (message.messageType == MsgType.EXIT_GROUP || message.messageType == MsgType.REMOVE_GROUP){
  612. // avatar = avatar.filter(val=>{
  613. // return !message.avatar.includes(val);
  614. // })
  615. // }
  616. unReadNum = sessions[index].unReadNum + 1;
  617. // 更新已有会话
  618. const updated = {
  619. ...sessions[index],
  620. message: lastMsg,
  621. updatedAt: time,
  622. unReadNum: type == 0 ? 0 : unReadNum
  623. // avatar
  624. };
  625. sessions.splice(index, 1);
  626. sessions.unshift(updated);
  627. } else {
  628. const isSelfSend = message.from === selfUuid;
  629. const newSession = {
  630. // uuid: message.messageType === 2 ? message.to : (isSelfSend ? message.to : message.from),
  631. uuid,
  632. name: message.toUsername || message.fromUsername || message.to || message.from,
  633. type: message.messageType == 2?'group':'user',
  634. message: lastMsg,
  635. updatedAt: time,
  636. avatar: message.avatar || '',
  637. unReadNum: type == 0 ? 0 : unReadNum
  638. };
  639. sessions.unshift(newSession);
  640. }
  641. systemStore.ImsessionList = [...sessions];
  642. // if(type != 0){
  643. // this.needRefreshIm +=1;
  644. // }
  645. this.needRefreshIm += 1;
  646. },
  647. // ************ 接收方 方法 ************//
  648. // 更新会话未读状态
  649. funUpdateUnread(uuid) {
  650. const systemStore = useSystemStore();
  651. let index = systemStore.ImsessionList ? systemStore.ImsessionList.findIndex(s => (s.uuid || s.id) === uuid) : -1;
  652. if (index > -1) {
  653. systemStore.ImsessionList[index].unReadNum = 0;
  654. }
  655. },
  656. // 申请好友数据
  657. funApplyfriend(message) {
  658. if (message.messageType == MsgType.MESSAGE_APPLY_FRIEND) {
  659. this.applyfriend[message.from] = 1;
  660. this.unread = true;
  661. }
  662. },
  663. // 删除会话
  664. funDeleteSessionMessage(message, msg) {
  665. if (message.messageType == MsgType.MESSAGE_DELETE_FRIEND || message.messageType == MsgType.DELETE_GROUP || message.messageType == MsgType.REMOVE_GROUP || message.messageType == MsgType.EXIT_GROUP) {
  666. // let msg;
  667. // try {
  668. // msg = JSON.parse(message.content);
  669. // } catch (e) { }
  670. if (msg?.users?.includes(message.to) || message.messageType == MsgType.DELETE_GROUP) {
  671. this.funDeleteDelAuth(message.from);
  672. this.deleteSessionChat(message.from);
  673. }
  674. }
  675. },
  676. // 恢复会话
  677. funRestoreSessionMessage(message) {
  678. if (message.messageType == MsgType.CREATE_GROUP || message.messageType == MsgType.JION_GROUP || message.messageType == MsgType.INVITATION_GROUP || message.messageType == MsgType.MESSAGE_PASS_FRIEND) {
  679. this.chatRefresh += 1;
  680. if (message.messageType == MsgType.JION_GROUP || message.messageType == MsgType.INVITATION_GROUP || message.messageType == MsgType.MESSAGE_PASS_FRIEND) {
  681. this.funRestoreDelAuth(message.from);
  682. }
  683. }
  684. },
  685. // 语音视频通知
  686. // 群通知
  687. funGroupNotice(msg){
  688. this.toUserInfo = {
  689. ...this.toUserInfo,
  690. notice: msg && msg.notice?msg.notice: this.toUserInfo.notice,
  691. nickname: msg && msg.name?msg.name:this.toUserInfo.nickname,
  692. }
  693. },
  694. // 群消息置顶
  695. funGroupTop(message = null) {
  696. },
  697. // ************ 发送方 方法 ************//
  698. // 删除好友申请
  699. deleteFriend(uuid){
  700. if (this.applyfriend[uuid]) {
  701. delete this.applyfriend[uuid]
  702. }
  703. this.unread = Object.keys(this.applyfriend).length > 0;
  704. },
  705. // 同意或者拒绝清空applyfriend数据
  706. funCancelfriend(message){
  707. if (message.messageType == MsgType.MESSAGE_REJECT_FRIEND || message.messageType == MsgType.MESSAGE_PASS_FRIEND) {
  708. // if (this.applyfriend[message.from]){
  709. // delete this.applyfriend[message.from]
  710. // }
  711. // this.unread = Object.keys(this.applyfriend).length > 0;
  712. this.deleteFriend(message.from);
  713. }
  714. },
  715. // ************ 公用 ************//
  716. //恢复会话权限
  717. funRestoreDelAuth(uuid) {
  718. if (this.chatDelAuth[uuid]) {
  719. delete this.chatDelAuth[uuid]
  720. }
  721. },
  722. // 禁用会话权限
  723. funDeleteDelAuth(uuid){
  724. this.chatDelAuth[uuid] = 1;
  725. },
  726. // 初始化好友申请数据
  727. async funInitfriend(uuid){
  728. if (Object.keys(this.applyfriend).length > 0){
  729. this.unread = true;
  730. return
  731. };
  732. const res = await friendRequest({ uuid, status: 1,state:1 });
  733. if (res.data && res.data.length > 0){
  734. res.data.forEach(val=>{
  735. this.applyfriend[val.uuid] = 1
  736. })
  737. }
  738. this.unread = res.data && res.data.length > 0;
  739. },
  740. // 删除会话列表
  741. deleteSessionChat(uuid) {
  742. const systemStore = useSystemStore();
  743. let sessions = systemStore.ImsessionList ? [...systemStore.ImsessionList] : [];
  744. let index = sessions.findIndex(s => (s.uuid || s.id) === uuid);
  745. if (index > -1) {
  746. sessions.splice(index, 1);
  747. systemStore.ImsessionList = sessions;
  748. }
  749. },
  750. // 群成员列表
  751. async fetchGroupMembers(){
  752. if (this.toUserInfo.type == 'group'){
  753. if (this.groupMembersList[this.toUserInfo.uuid]) {
  754. return this.groupMembersList[this.toUserInfo.uuid]
  755. }
  756. try {
  757. const res = await groupList(this.toUserInfo.uuid);
  758. this.groupMembersList[this.toUserInfo.uuid] = res.data || [];
  759. return res.data
  760. } catch (e) {
  761. console.error('获取群成员失败', e);
  762. return []
  763. }
  764. }
  765. }
  766. },
  767. });