wujingjing
2025-02-07 4c20089472b20319746649decbce3a11f16cb6a0
src/components/chat/smallChat/index.vue
@@ -1,6 +1,6 @@
<template>
   <div ref="chatContainerRef" :style="chatContainerStyle" class="opacity-90 small-chat-container" @mousedown="startDrag">
      <div class="bg-white rounded-lg shadow-lg flex flex-col w-[370px] max-h-[600px] absolute bottom-4 right-4">
      <div class="bg-white rounded-lg shadow-lg flex flex-col w-[370px] max-h-[540px] absolute bottom-4 right-4">
         <!-- 头部 -->
         <div
            ref="chatHeaderRef"
@@ -8,7 +8,7 @@
            class="small-chat-header h-12 flex items-center justify-between px-4"
            style="border-bottom: 1px solid #e0e0e0"
         >
            <div class="text-lg font-bold">WI水务智能助手</div>
            <div class="text-lg font-bold py-2">WI水务智能助手</div>
            <div class="flex items-center gap-2">
               <!-- <el-icon class="cursor-pointer text-gray-400 hover:text-gray-600">
               <Refresh />
@@ -73,19 +73,51 @@
                  </div> -->
               </div>
            </div>
            <div v-else class="flex flex-col gap-4">
            <div v-else class="flex flex-col gap-1.5">
               <!-- 对话内容 -->
               <div class="flex flex-col gap-4" v-for="item in historyMessages" :key="item.id">
               <div class="flex flex-col gap-4" v-for="(item, index) in historyMessages" :key="item.id">
                  <!-- 用户提问 -->
                  <div class="flex gap-3" v-if="item.role === 'user'">
                  <div class="flex gap-3 items-center" v-if="item.role === 'user'">
                     <img :src="userPic" class="w-10 h-10" alt="用户头像" />
                     <div class="flex-1 bg-blue-100">
                        <div class="p-4 rounded-lg">{{ item.content.value }}</div>
                     <div class="flex-1 bg-blue-100 rounded-lg">
                        <div class="p-3  flex items-center">
                           <span>
                              {{ item.content.value }}
                           </span>
                           <!-- #region ====================== 回复反馈 ======================-->
                           <el-icon v-if="(historyMessages[index+1].content as AssistantContent).isLoading" class="ml-2 animate-spin"
                              ><Loading
                           /></el-icon>
                           <template v-else>
                              <span
                                 v-if="(historyMessages[index+1].content as AssistantContent).isError"
                                 class="flex items-center ml-4 text-danger before:content-['('] after:content-[')']"
                              >
                                 {{ (historyMessages[index + 1].content as AssistantContent).value }}
                                 <el-tooltip
                                    v-if="(historyMessages[index + 1].content as AssistantContent).reason"
                                    :content="(historyMessages[index + 1].content as AssistantContent).reason"
                                    placement="top"
                                 >
                                    <el-icon class="flex-center cursor-pointer ml-1">
                                       <question-filled />
                                    </el-icon>
                                 </el-tooltip>
                              </span>
                              <span v-else class="ml-4 text-success before:content-['('] after:content-[')']">
                                 {{ (historyMessages[index + 1].content as AssistantContent).value }}
                              </span>
                           </template>
                           <!-- #endregion -->
                        </div>
                     </div>
                  </div>
                  <!-- AI回答 -->
                  <div class="flex gap-3" v-else-if="item.role === 'assistant'">
                  <!-- <div class="flex gap-3" v-else-if="item.role === 'assistant'">
                     <img :src="assistantPic" class="w-10 h-10" alt="AI头像" />
                     <div class="flex-1 bg-gray-100">
                        <div v-if="(item.content as AssistantContent)?.isLoading" class="p-4 rounded-lg flex items-center">
@@ -96,7 +128,7 @@
                           {{ item.content.value }}
                        </div>
                     </div>
                  </div>
                  </div> -->
               </div>
            </div>
         </div>
@@ -120,6 +152,7 @@
import assistantPic from '/static/images/role/assistant-200x192.png';
import userPic from '/static/images/role/user-200x206.png';
import { useDrag } from '/@/hooks/useDrag';
import { cloneDeep, defaults } from 'lodash-es';
const props = defineProps<{
   olMap?: OLMap;
@@ -206,22 +239,33 @@
         }
         if (chunkRes.mode === 'finish') {
            if (!haveMapOperate) {
               refreshAssistantMessage({ value: `未识别到操作:${question}`, isError: true });
               refreshAssistantMessage({ reason: `未识别到操作:"${question}"` });
            }
         }
      }
   ).catch((error) => {
      Logger.error('agent stream error:\n\n' + error);
      refreshAssistantMessage();
      refreshAssistantMessage({ reason: 'AI回答失败' });
   });
};
const refreshAssistantMessage = (content: Partial<AssistantContent> = { value: 'AI回答失败', isError: true }) => {
const refreshAssistantMessage = (
   content: Partial<AssistantContent> = { value: '失败', isError: true, reason: '', isLoading: false }
) => {
   const cloneContent = cloneDeep(content);
   const last = getLastAssistantMessage();
   content = defaults(cloneContent, {
      value: '失败',
      isError: true,
      reason: '',
      isLoading: false,
   });
   if (last) {
      last.content.value = content.value;
      last.content.isLoading = content.isLoading;
      last.content.isError = content.isError ?? false;
      for (const key in content) {
         if (Object.prototype.hasOwnProperty.call(content, key)) {
            last.content[key] = content[key];
         }
      }
   }
};
@@ -256,7 +300,7 @@
         props.olMap.adjustViewToMarkers();
         break;
   }
   refreshAssistantMessage({ value: `${command.operate}成功` });
   refreshAssistantMessage({ value: `成功`, isError: false });
};
const scrollToBottom = () => {