wujingjing
2025-04-07 457cc6cf166d3b6c22be4f78c1db8802a7fbb4c7
src/components/chat/smallChat/index.vue
@@ -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 py-2">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 />
@@ -39,7 +39,7 @@
               <!-- 欢迎语 -->
               <!-- <div class="flex flex-col items-center gap-1.5 mt-8">
                  <div class="text-lg">你好, 我是</div>
                  <div class="text-lg text-blue-500">WI水务智能助手</div>
                  <div class="text-lg text-blue-500">WI水务智能平台</div>
                  <span class="text-lg">你可以输入以下问题,进行地图操作</span>
               </div> -->
               <!-- 快捷问题 -->
@@ -134,7 +134,14 @@
         <!-- 底部输入框 -->
         <div class="p-2 border-t">
            <ChatInput v-model="inputText" @sendClick="sendClick" @toggleHistory="toggleHistory" :showHistory="showHistory" />
            <ChatInput
               :isTalking="lastIsLoading"
               v-model="inputText"
               @sendClick="sendClick"
               @toggleHistory="toggleHistory"
               @stopGenClick="stopGenClick"
               :showHistory="showHistory"
            />
         </div>
      </div>
      <Teleport to="body">
@@ -144,21 +151,23 @@
</template>
<script setup lang="ts" name="smallChat">
import type { CancelTokenSource } from 'axios';
import axios from 'axios';
import { cloneDeep, defaults } from 'lodash-es';
import { fromLonLat } from 'ol/proj';
import { computed, nextTick, onMounted, ref } from 'vue';
import ChatInput from './ChatInput.vue';
import type { ChatMessage } from './types';
import { AssistantContent } from './types';
import WorkOrderDlg from './WorkOrderDlg.vue';
import { agentStreamByPost } from '/@/api/ai/chat';
import { getSearchMapElement } from '/@/api/map';
import { useDrag } from '/@/hooks/useDrag';
import { Logger } from '/@/model/logger/Logger';
import { GaoDeSourceType, gaoDeSourceTypeMap, type OLMap } from '/@/model/map/OLMap';
import userPic from '/static/images/role/user-200x206.png';
import { getSearchMapElement } from '/@/api/map';
import { formatDate } from '/@/utils/formatTime';
import { systemGlobalConfig } from '/@/stores/global';
import { fromLonLat } from 'ol/proj';
import { formatDate } from '/@/utils/formatTime';
import userPic from '/static/images/role/user-200x206.png';
const props = defineProps<{
   olMap?: OLMap;
}>();
@@ -199,12 +208,17 @@
   { title: '创建工单', question: '松福大道DN800松岗联通监测设备没有数据,创建一个设备维修工单,请及时派人维修。' },
]);
const chatContentRef = ref<HTMLDivElement>(null);
const getLastAssistantMessage = () => {
   const last = historyMessages.value[historyMessages.value.length - 1];
   const result = last.role === 'assistant' ? last : null;
   const result = last?.role === 'assistant' ? last : null;
   return result as ChatMessage<AssistantContent>;
};
const lastIsLoading = computed(() => {
   const last = getLastAssistantMessage();
   const loading = last?.content?.isLoading ?? false;
   return loading;
});
//#region ====================== 添加工单 ======================
const optDlgIsShow = ref(false);
@@ -247,13 +261,11 @@
const handleSwitchLayer = (formData: { layerId: string; visible: boolean }) => {
   props.olMap.setLayerVisible(formData.layerId, formData.visible);
   refreshAssistantMessage({ value: `成功`, isError: false });
};
const changeTheme = (formData: { themeId: string }) => {
   props.olMap.setThemeById(formData.themeId);
   refreshAssistantMessage({ value: `成功`, isError: false });
};
const handleQueryObject = async (formData: { objectName: string }) => {
@@ -312,11 +324,15 @@
   props.olMap.setSourceType(formData.LayerId as GaoDeSourceType);
   refreshAssistantMessage({ value: `成功`, isError: false });
};
let lastAxiosSource: CancelTokenSource = null;
const startStream = (question: string) => {
   if (lastIsInit) {
      showHistory.value = false;
   }
   const currentSource = axios.CancelToken.source();
   lastAxiosSource = currentSource;
   // if (question === '松福大道DN800松岗联通监测设备没有数据,创建一个设备维修工单,请及时派人维修。') {
   //    setTimeout(() => {
   //       openOptDlg();
@@ -337,7 +353,7 @@
         if (
            chunkRes.type === 'string' &&
            ['create_work_order', 'switch_layers', 'switch_topic', 'query_address', 'query_object'].includes(chunkRes.mode)
            ['create_work_order', 'switch_layers', 'switch_topic', 'query_address', 'query_object', 'map'].includes(chunkRes.mode)
         ) {
            const jsonData = JSON.parse(chunkRes.value);
@@ -371,6 +387,10 @@
                  haveMapOperate = true;
                  handleQueryObject(jsonData);
                  break;
               case 'map':
                  haveMapOperate = true;
                  handleMapCommand(jsonData);
                  break;
            }
         }
@@ -379,6 +399,9 @@
               refreshAssistantMessage({ reason: `未识别到操作:"${question}"` });
            }
         }
      },
      {
         cancelToken: currentSource.token,
      }
   ).catch((error) => {
      Logger.error('agent stream error:\n\n' + error);
@@ -515,6 +538,17 @@
   });
};
//#endregion
//#region ====================== 流停止 ======================
const stopGenClick = () => {
   lastAxiosSource?.cancel();
   const last = getLastAssistantMessage();
   if (!last) return;
   last.content.isLoading = false;
   last.content.isError = true;
   last.content.reason = '用户停止操作';
};
//#endregion
onMounted(() => {});
</script>