webSocketStore.js 29 KB

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