wujingjing
2025-04-02 5fb58c10b2bb44b3f2d3bdab4d7a6619271e2bbf
src/components/chat/hooks/useSyncMsg.ts
@@ -1,65 +1,99 @@
import { differenceBy } from 'lodash-es';
import moment from 'moment';
import { onActivated, onDeactivated, unref, type Ref } from 'vue';
import { RoleEnum, type ChatMessage } from '../model/types';
import { QueryHistoryDetail } from '/@/api/ai/chat';
import { sseClient } from '/@/stores/global';
import { LOAD_CHAT_LIMIT } from '../constants';
import { differenceBy } from 'lodash-es';
import { Logger } from '/@/model/logger/Logger';
import { ElNotification } from 'element-plus';
type UseSyncMsgOptions = {
   updateLoadIndex: (addCount: number) => void;
   msgList: Ref<ChatMessage[]>;
   historyGroupId: string | Ref<string>;
   checkCanSync: (data: any) => boolean;
   loadReplyData: (data: any) => Promise<ChatMessage[]>;
   scrollToBottom: () => void;
   showTip: (data: any) => void;
};
export const useSyncMsg = (options: UseSyncMsgOptions) => {
   const { updateLoadIndex, msgList, historyGroupId } = options;
   const { updateLoadIndex, msgList, historyGroupId, checkCanSync, loadReplyData, scrollToBottom, showTip } = options;
   // const loadRangeData = async (lastEnd = nextUserMsgEndIndex) => {
   //    const res = await QueryHistoryDetail({
   //       history_group_id: unref(historyGroupId),
   //       last_end: lastEnd,
   //       last_count: LOAD_CHAT_LIMIT,
   //    });
   //    const result: ChatMessage[] = res.details ?? [];
   //    if (result.length) {
   //       nextUserMsgEndIndex += result.length;
   //       const rangeMsgList = await loadReplyData(res.details);
   //       messageList.value.unshift(...rangeMsgList);
   //    } else {
   //       isNoMore = true;
   //    }
   const insertSyncMsg = (replayData: any[]) => {
      const insertResult: { index: number; item: any }[] = [];
      for (let i = replayData.length - 1; i >= 0; i--) {
         const insertItem = replayData[i];
         if (insertItem.role === RoleEnum.assistant) continue;
         for (let j = msgList.value.length - 1; j >= 0; j--) {
            const currentItem = msgList.value[j];
            if (currentItem.role === RoleEnum.assistant) continue;
            if (moment(insertItem.createTime).isAfter(currentItem.createTime)) {
               const insertAssistantItem = replayData[i + 1];
               insertResult.push({
                  index: j + 2,
                  item: [insertItem, insertAssistantItem],
               });
               break;
            }
         }
      }
      insertResult.forEach((resultItem) => {
         msgList.value.splice(resultItem.index, 0, ...resultItem.item);
      });
   };
   //    return result;
   // };
   const historyUpdate = async (data: any) => {
      if (!checkCanSync(data)) return;
      if (!data) return;
      const groupId = unref(historyGroupId);
      if (!groupId) return;
      if (data?.type === 'chat_start') {
         const groupId = unref(historyGroupId);
         const startGroupId = data?.history_group_id;
         if (groupId !== startGroupId) return;
         showTip(data);
      }
      if (data?.type === 'chat_history_id') {
         const groupId = unref(historyGroupId);
         if (!groupId) return;
         const recentIds = data.id_list ?? [];
         const recentGroupHistoryIds = recentIds.filter((item) => item.group_id === groupId);
         if (recentGroupHistoryIds.length === 0) return;
         const userHistoryIds = msgList.value
            .filter((item) => item.role === RoleEnum.user)
            .map((item) => ({ id: item.historyId, time: item.createTime }));
         const unSyncedHistoryIds = differenceBy(recentIds, userHistoryIds, 'id');
         console.log('unSyncedHistoryIds', unSyncedHistoryIds);
            .map((item) => ({ history_id: item.historyId, time: item.createTime }));
         const tmpUnSyncedHistoryIds = differenceBy(recentGroupHistoryIds, userHistoryIds, 'history_id') as any[];
         const latestUserHistory = userHistoryIds[userHistoryIds.length - 1];
         let unSyncedHistoryIds = tmpUnSyncedHistoryIds;
         // 太晚的不需要更新
         if (latestUserHistory) {
            unSyncedHistoryIds = tmpUnSyncedHistoryIds.filter((item) => moment(item.time).isAfter(latestUserHistory.time));
         }
         if (!unSyncedHistoryIds || unSyncedHistoryIds.length === 0) return;
         const res = await QueryHistoryDetail({
            history_group_id: groupId,
            id_list: unSyncedHistoryIds.map((item) => item.history_id).join(','),
         });
         if (!checkCanSync(data)) return;
         const result: ChatMessage[] = res.details ?? [];
         if (!result || result.length === 0) return;
         const replayData = await loadReplyData(res.details);
         if (!checkCanSync(data)) return;
         insertSyncMsg(replayData);
         updateLoadIndex(unSyncedHistoryIds.length);
         scrollToBottom();
      }
      const res = await QueryHistoryDetail({
         history_group_id: groupId,
         last_end: 0,
         last_count: LOAD_CHAT_LIMIT,
      });
      console.log('historyUpdate', data, groupId);
   };
   onActivated(() => {
      console.log('onActivated');
      sseClient.subscribe(historyUpdate);
      sseClient?.subscribe(historyUpdate);
   });
   onDeactivated(() => {
      console.log('onDeactivated');
      sseClient.unsubscribe(historyUpdate);
      sseClient?.unsubscribe(historyUpdate);
   });
   // onUnmounted(() => {