| | |
| | | :loading="chatListLoading" |
| | | :more-is-loading="moreIsLoading" |
| | | :is-share-page="isSharePage" |
| | | :isTalking="isTalking" |
| | | ref="containerRef" |
| | | @autoSendMessage="autoSendMessage" |
| | | > |
| | |
| | | } |
| | | |
| | | // 强制触发更新 |
| | | |
| | | scrollToBottom(); |
| | | }, |
| | | { |
| | |
| | | ) => { |
| | | updateLoadIndex(); |
| | | updateInfo(userItem, assistantItem, resMsgContent, other); |
| | | setTimeout(() => { |
| | | // 收到回复,继续滚 |
| | | scrollToBottom(); |
| | | }, 300); |
| | | // setTimeout(() => { |
| | | // // 收到回复,继续滚 |
| | | // scrollToBottom(); |
| | | // }, 300); |
| | | }; |
| | | const sendChatMessage = async (content: ChatContent = messageContent.value, lifecycleCall?: QuestionLifecycle) => { |
| | | if (!checkCanSend(content)) { |
| | |
| | | @toggleFullScreen="toggleFullScreen" |
| | | ></PanelTool> |
| | | |
| | | <Search class="absolute top-0 left-2 z-14 w-fit" :olMap="olMap" :propertyMap="propertyMap" :propertyConfigMap="propertyConfigMap"/> |
| | | <Search |
| | | class="absolute top-0 left-2 z-14 w-fit" |
| | | :olMap="olMap" |
| | | :propertyMap="propertyMap" |
| | | :propertyConfigMap="propertyConfigMap" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | }; |
| | | const addMarkerLayer = () => { |
| | | const map = props.data.map; |
| | | if (map.pos_x == null && map.pos_y == null) return; |
| | | const dataList = (props.data?.values ?? []).map((item) => { |
| | | const x = item[map.pos_x]; |
| | | const y = item[map.pos_y]; |
| | | if (map.pos_x == null || map.pos_y == null) return; |
| | | const dataList = (props.data?.values ?? []) |
| | | .filter((item) => { |
| | | const x = item[map.pos_x]; |
| | | const y = item[map.pos_y]; |
| | | if (x === null || y == null) { |
| | | return false; |
| | | } else { |
| | | return true; |
| | | } |
| | | }) |
| | | .map((item) => { |
| | | const x = item[map.pos_x]; |
| | | const y = item[map.pos_y]; |
| | | |
| | | return { |
| | | position: [x, y], |
| | | // textColor: item.color, |
| | | extData: { |
| | | value: item, |
| | | recordSetTable: props.data, |
| | | }, |
| | | }; |
| | | }); |
| | | return { |
| | | position: [x, y], |
| | | // textColor: item.color, |
| | | extData: { |
| | | value: item, |
| | | recordSetTable: props.data, |
| | | }, |
| | | }; |
| | | }); |
| | | |
| | | olMap.value.addMarkerLayer(dataList, { |
| | | markerOpt: { |
| | | icon: { |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { onActivated, onDeactivated, ref } from 'vue'; |
| | | import { onActivated, onDeactivated, ref, toRef, toRefs } from 'vue'; |
| | | import { useChatWidth } from '../hooks/useChatWidth'; |
| | | import { useScroll } from '../hooks/useScroll'; |
| | | import type { QuestionLifecycle } from '../types'; |
| | |
| | | loading?: boolean; |
| | | moreIsLoading?: boolean; |
| | | isSharePage?: boolean; |
| | | isTalking?: boolean; |
| | | }>(); |
| | | |
| | | const emit = defineEmits<{ |
| | | autoSendMessage: [string, QuestionLifecycle]; |
| | | }>(); |
| | | |
| | | const { isTalking } = toRefs(props); |
| | | |
| | | const chatListDom = ref<HTMLDivElement>(); |
| | | const { openDigitalHuman, isHumanTalking, humanIsLoading, digitalHumanIsShow, closeDigitalHuman, digitalHumanWidth } = useDigitalHuman( |
| | |
| | | ); |
| | | const { scrollToBottom, isBottom } = useScroll({ |
| | | chatListDom, |
| | | isTalking: isTalking, |
| | | }); |
| | | |
| | | const fileContentIsShow = ref(false); |
| | |
| | | import type { ChatMessage } from '../model/types'; |
| | | import emitter from '/@/utils/mitt'; |
| | | import { debounce } from '/@/utils/util'; |
| | | import { useEventListener } from '@vueuse/core'; |
| | | |
| | | export type UseScrollOption = { |
| | | chatListDom: Ref<HTMLDivElement>; |
| | | isTalking: Ref<boolean>; |
| | | }; |
| | | |
| | | export const useScroll = (option: UseScrollOption) => { |
| | | const { chatListDom } = option; |
| | | const { chatListDom, isTalking } = option; |
| | | const scrollStepToBottom = () => { |
| | | const allStepList = document.querySelectorAll('.step-list'); |
| | | const lastStepList = allStepList[allStepList.length - 1]; |
| | | if (!lastStepList) return; |
| | | lastStepList.scrollTop = lastStepList.scrollHeight - lastStepList.clientHeight; |
| | | }; |
| | | |
| | | let isScroll = false; |
| | | const scrollToBottom = () => { |
| | | if (isScroll) return; |
| | | nextTick(() => { |
| | | if (chatListDom.value.scrollHeight > chatListDom.value.clientHeight) { |
| | | chatListDom.value.scrollTop = chatListDom.value.scrollHeight - chatListDom.value.clientHeight; |
| | |
| | | }); |
| | | }; |
| | | |
| | | useEventListener(chatListDom, 'scroll', () => { |
| | | if (!isTalking.value) return; |
| | | if (isScroll) return; |
| | | isScroll = true; |
| | | }); |
| | | |
| | | watch( |
| | | () => isTalking.value, |
| | | (val) => { |
| | | if (!val) { |
| | | isScroll = false; |
| | | } |
| | | } |
| | | ); |
| | | |
| | | const scrollToTop = () => { |
| | | nextTick(() => { |
| | | chatListDom.value.scrollTop = 0; |
| | |
| | | }; |
| | | |
| | | const checkIsBottom = () => { |
| | | const bottom = Math.abs(chatListDom.value.scrollTop + chatListDom.value.clientHeight - chatListDom.value.scrollHeight) < 2; |
| | | if (bottom) { |
| | | isScroll = false; |
| | | } |
| | | // 误差 2像素 |
| | | isBottom.value = Math.abs(chatListDom.value.scrollTop + chatListDom.value.clientHeight - chatListDom.value.scrollHeight) < 2; |
| | | isBottom.value = bottom; |
| | | }; |
| | | const isBottom = ref(true); |
| | | onMounted(() => { |