wujingjing
2025-04-09 dd58c1d3a27ba48a5df050aab7c586bb9b988914
src/components/chat/Chat.vue
@@ -48,23 +48,25 @@
<script setup lang="ts">
import type { CancelTokenSource } from 'axios';
import axios from 'axios';
import { orderBy } from 'lodash-es';
import { ElMessage } from 'element-plus';
import moment from 'moment';
import { v4 as uuidv4 } from 'uuid';
import { computed, nextTick, onActivated, onMounted, ref } from 'vue';
import { loadAmisSource } from '../amis/load';
import ChatContainer from './components/ChatContainer.vue';
import ShareLinkDlg from './components/shareLink/index.vue';
import type { SendMsg } from './hooks/types';
import { useLoadData } from './hooks/useLoadData';
import { useScrollLoad } from './hooks/useScrollLoad';
import { useSyncMsg } from './hooks/useSyncMsg';
import MessageList from './messageList/index.vue';
import type { ChatContent } from './model/types';
import { AnswerState, AnswerType, RoleEnum, type ChatMessage } from './model/types';
import { getShareChatJsonByPost, questionStreamByPost } from '/@/api/ai/chat';
import PlayBar from '/@/components/chat/components/playBar/PlayBar.vue';
import CustomDrawer from '/@/components/drawer/CustomDrawer.vue';
import { Logger } from '/@/model/logger/Logger';
import { triggerRef } from 'vue';
import { ElLoadingService, ElMessage } from 'element-plus';
import ChatContainer from './components/ChatContainer.vue';
import ShareLinkDlg from './components/shareLink/index.vue';
import router from '/@/router';
import MessageList from './messageList/index.vue';
import {
   activeChatRoom,
   activeGroupType,
@@ -74,14 +76,15 @@
   isSharePage,
   roomConfig,
} from '/@/stores/chatRoom';
import { ParentRegister } from '/@/stores/global';
import emitter from '/@/utils/mitt';
import { deepClone } from '/@/utils/other';
import { useCompRef } from '/@/utils/types';
import { toFormData, toMyFixed } from '/@/utils/util';
import { useLoadData } from './hooks/useLoadData';
import { useSyncMsg } from './hooks/useSyncMsg';
import { getCurrentPosition } from '/@/utils/brower';
const containerRef = useCompRef(ChatContainer);
const chatListDom = computed(() => containerRef.value?.chatListDom);
const scrollToBottom = () => {
   containerRef.value?.scrollToBottom();
};
@@ -124,6 +127,8 @@
   });
};
const enableCallback = ref(false);
let streamOutputIsStart = false;
let position: Position = null;
const questionAi = async (text) => {
@@ -147,6 +152,10 @@
      params.tables = JSON.stringify(tableList);
   }
   const metricList = attachList.value.filter((item) => item.type === 'metric').map((item) => item.model);
   if (metricList?.length > 0) {
      params.metrics = JSON.stringify(metricList);
   }
   // if (!position) {
   //    const loadingInstance = ElLoadingService({
   //       text: '获取位置中...',
@@ -227,6 +236,26 @@
               // chunkRes.value = '准备数据分析';
            }
            if (chunkRes.mode === 'main_frame') {
               const jsonObj = JSON.parse(chunkRes.value);
               if (!enableCallback.value) {
                  return;
               }
               ParentRegister.notify?.({
                  type: 'main_frame',
                  value: jsonObj,
               });
               return;
            }
            if (chunkRes.mode === 'create_work_order') {
               const lastMsg = computedMessageList.value.at(-1);
               lastMsg.modeContent = chunkRes;
               triggerRefresh();
               return;
            }
            if (chunkRes.mode === 'summary') {
               const lastMsg = computedMessageList.value.at(-1);
               const extraContent = parseExtraContent(chunkRes.value);
@@ -276,11 +305,11 @@
            if (chunkRes.mode === 'conclusion') {
               const lastReport = computedMessageList.value.at(-1)?.content?.values?.at(-1);
               chunkRes.value = '分析结束';
               if (lastReport) {
                  lastReport.conclusion = chunkRes.value;
               }
               chunkRes.value = '分析结束';
            }
            const getLastGroup = () => {
               const lastGroup = computedMessageList.value.at(-1).stepGroup[0];
@@ -402,12 +431,27 @@
let currentLLMId = null;
const stopGenClick = () => {
const resetTalking = () => {
   lastAxiosSource?.cancel();
   isTalking.value = false;
   chatListLoading.value = false;
   streamOutputIsStart = false;
};
const stopGenClick = () => {
   resetTalking();
   if (isFrontQuestion) {
      ParentRegister.notify?.({
         type: 'msg_stop',
      });
   }
   computedMessageList.value.at(-1).isStopMsg = true;
};
const finishFrontQuestion = () => {
   resetTalking();
   ParentRegister.updateChildCallObj('sendMsg', null);
};
const checkCanSend = (content: ChatContent = messageContent.value) => {
@@ -423,11 +467,12 @@
const addChatItem = (content: ChatContent) => {
   isTalking.value = true;
   const userItem: ChatMessage = { role: RoleEnum.user, content, isChecked: false, attachList: attachList.value } as any;
   const userItem: ChatMessage = { role: RoleEnum.user, content, isChecked: false, attachList: deepClone(attachList.value) } as any;
   const assistantItem: ChatMessage = {
      role: RoleEnum.assistant,
      content: {
         type: AnswerType.Report,
         values: [],
      },
      state: AnswerState.Null,
      stepGroup: [
@@ -455,10 +500,57 @@
   playBarRef.value?.clearAttach();
};
const updateUserInfo = (userItem: ChatMessage, other: { historyId: string; question: string }) => {
   userItem.historyId = other.historyId;
   const current = moment().format('YYYY-MM-DD HH:mm:ss');
   userItem.createTime = current;
   userItem.content.values = other.question ?? userItem.content.values;
};
const updateAssistantInfo = (
   assistantItem: ChatMessage,
   resMsgContent: ChatContent,
   other: { historyId: string; question: string }
) => {
   const current = moment().format('YYYY-MM-DD HH:mm:ss');
   assistantItem.historyId = other.historyId;
   const currentTime = formatShowTimeYear(current);
   assistantItem.createTime = currentTime;
   assistantItem.content = resMsgContent;
};
const updateInfo = (
   userItem: ChatMessage,
   assistantItem: ChatMessage,
   resMsgContent: ChatContent,
   other: {
      historyId: string;
      question: string;
   }
) => {
   updateUserInfo(userItem, other);
   updateAssistantInfo(assistantItem, resMsgContent, other);
};
const handleAfterQuestion = (
   userItem: ChatMessage,
   assistantItem: ChatMessage,
   resMsgContent: ChatContent,
   other: { historyId: string; question: string }
) => {
   updateLoadIndex();
   updateInfo(userItem, assistantItem, resMsgContent, other);
   setTimeout(() => {
      // 收到回复,继续滚
      scrollToBottom();
   }, 300);
};
const sendChatMessage = async (content: ChatContent = messageContent.value) => {
   if (!checkCanSend(content)) {
      return;
   }
   isFrontQuestion = false;
   const isNewChat = messageList.value.length === 0;
   if (isNewChat) {
      if (activeSampleId.value) {
@@ -474,22 +566,96 @@
   try {
      const [userItem, assistantItem] = addChatItem(content);
      resMsgContent = await questionAi(content.values);
      updateLoadIndex();
      userItem.historyId = questionRes?.history_id;
      const current = moment().format('YYYY-MM-DD HH:mm:ss');
      userItem.createTime = current;
      userItem.content.values = questionRes?.question ?? userItem.content.values;
      assistantItem.historyId = questionRes?.history_id;
      const currentTime = formatShowTimeYear(current);
      assistantItem.createTime = currentTime;
      assistantItem.content = resMsgContent;
      setTimeout(() => {
         // 收到回复,继续滚
         scrollToBottom();
      }, 300);
      handleAfterQuestion(userItem, assistantItem, resMsgContent, {
         historyId: questionRes?.history_id,
         question: questionRes?.question,
      });
   } catch (error: any) {}
};
let isFrontQuestion = false;
const sendFrontChatMessage = async (content: ChatContent = messageContent.value): Promise<any> => {
   isFrontQuestion = true;
   const [userItem, assistantItem] = addChatItem(content);
   const promise = new Promise((resolve, reject) => {
      const receiveMsg = (msg: SendMsg) => {
         console.log('receiveMsg', msg);
         if (!assistantItem.content?.values) {
            assistantItem.content.values = [];
         }
         switch (msg.type) {
            case 'text':
               // 开始增加新的 stepGroup,后续的 stepGroup 并没有实际作用,只是为了做迭代用,迭代出组件,屎山代码实在太难改了!!!
               assistantItem.stepGroup.push({
                  value: [],
                  isShow: true,
               });
               assistantItem.content.values.push({
                  content: {
                     type: 'knowledge',
                     values: [
                        {
                           answer: msg.value,
                        },
                     ],
                  },
               });
               break;
            case 'select':
            case 'confirm':
            case 'input':
               // 开始增加新的 stepGroup,后续的 stepGroup 并没有实际作用,只是为了做迭代用,迭代出组件,屎山代码实在太难改了!!!
               assistantItem.stepGroup.push({
                  value: [],
                  isShow: true,
               });
               assistantItem.content.values.push({
                  content: {
                     type: 'content_cb',
                     values: msg,
                  },
               });
               break;
            case 'info':
               if (msg.value === 'finish') {
                  finishFrontQuestion();
                  return resolve({ userItem, assistantItem, resMsgContent: assistantItem.content });
               }
               break;
            default:
               break;
         }
         scrollToBottom();
         triggerRefresh();
      };
      ParentRegister.updateChildCallObj('sendMsg', receiveMsg);
   });
   return promise;
};
const questionSelf = (content: string) => {
   const myContent = { type: AnswerType.Text, values: content };
   if (!checkCanSend(myContent)) {
      return false;
   }
   sendFrontChatMessage(myContent).then(({ userItem, assistantItem, resMsgContent }) => {
      handleAfterQuestion(userItem, assistantItem, resMsgContent, {
         historyId: uuidv4(),
         question: content,
      });
   });
   return true;
};
const backQuestion = (content: { question: string; data: any }) => {
   sendChatMessage({ type: AnswerType.Text, values: content.question });
};
ParentRegister.updateChildCallObj('frontQuestion', questionSelf);
ParentRegister.updateChildCallObj('backQuestion', backQuestion);
const sendClick = () => {
   sendChatMessage(messageContent.value);