<template>
<!-- 看板管理-->
<div class="my_chatai_box">
<div class="up">
<div class="up_btn">
<img src="@/assets/images/drive/aiimg.png" alt="" />
<div class="txt">Chat Ai</div>
</div>
</div>
<div class="down">
<div class="down_up commonBox_left_mini" ref="messagesRef">
<div class="down_up_start">
<div v-if="currentObj.repeatTalksList.length == 0">
<chat-ai-robot :isTitle="true"></chat-ai-robot>
<!-- 默认初始状态 -->
<div class="tax">请把你的问题交给我吧</div>
</div>
<!-- 对话状态 -->
<div v-else>
<div
v-for="(item, index) in currentObj.repeatTalksList"
:key="index"
>
<div
class="ask"
style="
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: flex-end;
font-size: 14px;
color: #7a7687;
"
>
<div style="padding-right: 10px">{{ currentObj.name }}</div>
<div
style="
max-width: 80%;
text-align: right;
background: #fbfbfb;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
"
>
{{ item.ask }}
</div>
</div>
<div
class="anser"
style="
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: flex-start;
font-size: 14px;
color: #7a7687;
"
>
<chat-ai-robot
:isTitle="false"
:isLoading="item.isLoading"
></chat-ai-robot>
<div
style="
max-width: 80%;
background: #fbfbfb;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
"
>
{{ item.anser }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="down_input">
<el-input
class="input-box"
v-model="currentObj.inputTalks"
placeholder="给AI发送消息"
suffix-icon="el-icon-arrow-right"
@keyup.enter="sendMessage"
>
</el-input>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref, nextTick } from "vue";
import request from "@/API/request";
import serviceModule from "@/API/httpUrl";
import { ElMessage } from "element-plus";
import chatAiRobot from "./chatAiRobot.vue";
const currentObj = reactive({
inputTalks: "",
inputTalksCopy: "",
repeatTalksList: [],
inputTalksList: [],
name: "",
// 当前显示到的字符索引
currentIndex: 0,
// 定时器 ID
timer: null,
});
const getbasicUserInfo = async () => {
const { data, code, msg } = await request(serviceModule.basicUserInfo);
if (code === "0000") {
currentObj.name = data;
}
};
// 模拟发送消息的函数
const sendMessage = () => {
if (currentObj.inputTalks.trim() !== "") {
console.log("发送的消息:", currentObj.inputTalks);
currentObj.inputTalksList.push(currentObj.inputTalks);
currentObj.inputTalksCopy = currentObj.inputTalks;
currentObj.inputTalks = "";
currentObj.repeatTalksList.push({
ask: currentObj.inputTalksCopy,
anser: "",
anserFullText: "",
isLoading: true,
});
// 这里可以添加与后端交互发送消息给AI的逻辑
getAiChart(currentObj.inputTalksList);
}
};
const getAiChart = async (contents) => {
let params = {
contents,
};
const { data, code, msg } = await request(serviceModule.aiChart, params);
if (code === "0000") {
// return data;
// currentObj.repeatTalksList.push({
// ask: currentObj.inputTalksCopy,
// anser: data,
// });
currentObj.repeatTalksList[
currentObj.repeatTalksList.length - 1
].anserFullText = data;
currentObj.repeatTalksList[
currentObj.repeatTalksList.length - 1
].isLoading = false;
// console.log(currentObj.repeatTalksList, "对话内容");
startTyping(); //一个一个字的输出
scrollToLatestMessage();
} else {
ElMessage.error(msg);
}
};
const messagesRef = ref(null);
const startTyping = () => {
// 清除可能存在的旧定时器
clearInterval(currentObj.timer);
// 重置显示文本和索引
currentObj.repeatTalksList[currentObj.repeatTalksList.length - 1].anser = "";
currentObj.currentIndex = 0;
// 设置新的定时器
currentObj.timer = setInterval(() => {
if (
currentObj.currentIndex <
currentObj.repeatTalksList[currentObj.repeatTalksList.length - 1]
.anserFullText.length
) {
// 逐个添加字符到显示文本中
currentObj.repeatTalksList[currentObj.repeatTalksList.length - 1].anser +=
currentObj.repeatTalksList[
currentObj.repeatTalksList.length - 1
].anserFullText[currentObj.currentIndex];
currentObj.currentIndex++;
scrollToLatestMessage(); //这里执行一次 不然输入后对话框不会再最新的对话的位置
} else {
// 显示完所有字符后清除定时器
clearInterval(currentObj.timer);
}
}, 100); // 每个字符显示的间隔时间,单位为毫秒
};
// const scrollToLatestMessage = () => {
// if (messagesRef.value) {
// messagesRef.value.scrollTop = messagesRef.value.scrollHeight;
// }
// };
const scrollToLatestMessage = async () => {
// 等待DOM更新完成,确保列表已经渲染完毕
await nextTick();
if (messagesRef.value) {
const childElements = messagesRef.value.children;
if (childElements.length > 0) {
const lastElement = childElements[childElements.length - 1];
// 让列表容器滚动到最后一个元素的位置
messagesRef.value.scrollTop =
lastElement.offsetTop +
lastElement.offsetHeight -
messagesRef.value.offsetHeight;
}
}
};
onMounted(() => {
getbasicUserInfo();
});
</script>
<style scoped lang="less">
.my_chatai_box {
width: 100%;
height: 100%;
box-sizing: border-box;
background-color: #fff;
border-radius: 6px 6px 6px 6px;
.up {
box-sizing: border-box;
height: 64px;
background: #ffffff;
border-bottom: 1px solid #e5e4e7;
display: flex;
align-items: center;
.up_btn {
width: 92px;
height: 32px;
margin-left: 20px;
border-radius: 6px;
border: 1px solid;
border-image: linear-gradient(
94deg,
rgba(255, 129, 129, 1),
rgba(205, 111, 255, 1),
rgba(205, 111, 255, 1),
rgba(122, 146, 255, 1)
)
1 1;
display: flex;
align-items: center;
justify-content: center;
img {
width: 20px;
height: 20px;
margin-right: 3px;
}
.txt {
font-family: PingFang SC, PingFang SC;
font-size: 14px;
color: #7a7687;
}
}
}
.down {
height: calc(100% - 64px);
box-sizing: border-box;
background: #fff;
padding: 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
.down_up {
height: 0;
flex: 1;
box-sizing: border-box;
margin-bottom: 10px;
.down_up_start {
.tax {
width: 100%;
height: 60px;
box-sizing: border-box;
line-height: 60px;
background: #fbfbfb;
box-shadow: 0px 0px 2px 0px rgba(219, 199, 234, 0.25);
border-radius: 12px 12px 12px 12px;
border: 1px solid #f4f0ff;
padding-left: 20px;
font-size: 14px;
color: #7a7687;
}
}
.down_up_talking {
}
}
.down_input {
height: 80px;
// border: 1px solid #f4f0ff;
.input-box {
height: 100%;
background: #fff;
border-radius: 12px;
box-sizing: border-box;
// padding: 0 20px;
border: none;
box-shadow: none; /* 去掉默认的聚焦阴影 */
outline: none; /* 去掉聚焦时的轮廓线 */
}
}
.down_input :deep(.el-input__inner) {
border: none;
box-shadow: none; /* 去掉默认的聚焦阴影 */
outline: none; /* 去掉聚焦时的轮廓线 */
}
}
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架