<template>
|
<div class="flex h-full">
|
<div class="flex flex-col h-full flex-auto relative">
|
<!-- 消息列表区域 -->
|
<div v-resize="updateChatWidth" ref="chatListDom" class="relative h-full flex flex-col items-center overflow-y-auto flex-auto">
|
<span
|
class="more-loading absolute text-blue-400 left-[50%] translate-x-[-50%] cursor-pointer w-10"
|
v-loading="moreIsLoading"
|
/>
|
|
<div class="h-full relative" v-loading="loading" :style="{ width: chatWidth }">
|
<slot name="message-list" />
|
</div>
|
</div>
|
|
<!-- 回到底部按钮 -->
|
<div class="absolute right-28 bottom-72" v-if="!isBottom">
|
<div
|
class="flex items-center justify-center size-[38px] cursor-pointer hover:text-[#0284ff] border rounded-full hover:bg-[#f6f7f9] shadow bg-white"
|
@click="scrollToBottom"
|
>
|
<i class="ywifont ywicon-xiangxiajiantou !text-[20px]" />
|
</div>
|
</div>
|
<div
|
v-show="digitalHumanIsShow"
|
v-loading="humanIsLoading"
|
class="absolute right-0 bottom-6 z-[2]"
|
:style="{ width: digitalHumanWidth, height: `calc(${digitalHumanWidth} * 16 / 9 - 300px)`, overflow: 'hidden' }"
|
>
|
<span class="ywifont ywicon-guanbi text-[20px] cursor-pointer absolute top-2 right-8 z-[1]" @click="closeDigitalHuman"></span>
|
<div class="duix-container h-full w-full" :style="{ width: digitalHumanWidth, height: `calc(${digitalHumanWidth} * 16 / 9)` }"></div>
|
</div>
|
|
<div v-if="!digitalHumanIsShow" class="absolute rounded-full right-[24px] bottom-[100px] z-[2] bg-white p-4">
|
<el-tooltip content="数字人" placement="top">
|
<button class="digital-human-button " @click="openDigitalHuman">
|
<img alt="Icon" :src="iconSrc" />
|
</button>
|
<!-- <div
|
class="flex items-center justify-center size-[38px] cursor-pointer hover:text-[#0284ff] border rounded-full hover:bg-[#f6f7f9] shadow bg-white"
|
@click="openDigitalHuman"
|
>
|
<i class="ywifont ywicon-shuziren !text-[20px]" />
|
</div> -->
|
</el-tooltip>
|
</div>
|
|
<!-- 输入区域 -->
|
<div class="w-full px-6 pb-6 bg-[rgb(247,248,250)] flex justify-center z-[1] flex-0" v-if="!isSharePage">
|
<slot name="input-area" />
|
</div>
|
</div>
|
|
<div class="w-[30%] flex-0 flex flex-col" v-if="fileContentIsShow">
|
<div class="bg-[#f9fbff] flex items-center justify-between p-4 border-b">
|
<div class="text-lg font-medium">{{ fileContent.title }}</div>
|
<div class="cursor-pointer hover:text-[#0284ff]" @click="fileContentIsShow = false">
|
<i class="ywifont ywicon-guanbi text-[20px]" />
|
</div>
|
</div>
|
<span class="bg-[#edf2fb] flex-1 overflow-y-auto p-4 break-words whitespace-pre-wrap">
|
{{ fileContent.content }}
|
</span>
|
</div>
|
|
<slot name="drawer" />
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { onActivated, onDeactivated, ref } from 'vue';
|
import { useChatWidth } from '../hooks/useChatWidth';
|
import { useScroll } from '../hooks/useScroll';
|
import type { QuestionLifecycle } from '../types';
|
import { useDigitalHuman } from './playBar/hook/useDigitalHuman';
|
import { iconSrc } from './constants';
|
import emitter from '/@/utils/mitt';
|
const props = defineProps<{
|
loading?: boolean;
|
moreIsLoading?: boolean;
|
isSharePage?: boolean;
|
}>();
|
|
const emit = defineEmits<{
|
autoSendMessage: [string, QuestionLifecycle];
|
}>();
|
|
const chatListDom = ref<HTMLDivElement>();
|
const { openDigitalHuman, isHumanTalking, humanIsLoading, digitalHumanIsShow, closeDigitalHuman, digitalHumanWidth } = useDigitalHuman(
|
{
|
container: '.duix-container',
|
autoSendMessage: (question: string, lifecycleCall?: QuestionLifecycle) => {
|
emit('autoSendMessage', question, lifecycleCall);
|
},
|
}
|
);
|
const { scrollToBottom, isBottom } = useScroll({
|
chatListDom,
|
});
|
|
const fileContentIsShow = ref(false);
|
|
const fileContent = ref({
|
title: '',
|
content: '',
|
});
|
|
const setFileContent = (data: { title: string; content: string }) => {
|
fileContentIsShow.value = true;
|
fileContent.value = data;
|
};
|
|
onActivated(() => {
|
emitter.on('setFileContent', setFileContent);
|
});
|
|
onDeactivated(() => {
|
emitter.off('setFileContent', setFileContent);
|
});
|
|
const { updateChatWidth, chatWidth } = useChatWidth();
|
|
defineExpose({
|
chatListDom,
|
scrollToBottom,
|
chatWidth,
|
});
|
</script>
|
|
<style scoped>
|
.more-loading :deep(.el-loading-spinner) {
|
--loading-size: 35px;
|
margin-top: 0;
|
.circular {
|
width: var(--loading-size);
|
height: var(--loading-size);
|
}
|
}
|
|
.digital-human-button {
|
width: 40px;
|
height: 40px;
|
border: none;
|
border-radius: 50%;
|
background-color: #ffffff;
|
cursor: pointer;
|
padding: 0;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
transition: all 0.3s ease;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
.digital-human-button:hover {
|
transform: translateY(-2px);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
}
|
|
.digital-human-button:active {
|
transform: translateY(0);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
}
|
|
.digital-human-button img {
|
width: 48px;
|
height: 48px;
|
object-fit: contain;
|
}
|
</style>
|