Files
Situation-Awareness-Platfor…/src/views/Jyh/KnowledgeHub/Components/AIModal.vue

280 lines
6.6 KiB
Vue
Raw Normal View History

<template>
<d-modal
v-model="visible"
title="AI问答"
@ok="handleClose"
:cancel="handleClose"
style="width: 900px;"
>
<div class="log-content">
<McLayout>
<!-- <McLayoutHeader>
<McHeader :logoImg="'/logo.svg'" :title="'MateChat'"></McHeader>
</McLayoutHeader>-->
<McLayoutContent v-if="visible" style="margin: 16px 0;">
<div ref="conversationRef" class="conversation-area">
<!-- 欢迎提示 -->
<div v-if="messages.length === 0" class="welcome-message">
<div class="welcome-page">
<div class="home-title">
<img src="@/assets/imgs/jyh/aiLogo2.png" alt="logo" />
<h1>TcodeAI助手</h1>
</div>
<div class="home-detail">
<div class="home-detail-1">Hi欢迎使用TcodeAI助手</div>
<div class="home-detail-2">TcodeAI助手 可以辅助研发人员进行软件查询批量校验查看软件详情等</div>
<div class="home-detail-2">作为AI模型TcodeAI助手 提供的答案可能不总是确定或准确的但您的反馈可以帮助 TcodeAI助手 做得更好</div>
</div>
</div>
<!-- <div class="welcome-icon">-->
<!-- <i class="fa fa-comment-dots"></i>-->
<!-- </div>-->
<!-- <div class="welcome-text">-->
<!-- <h3>请输入你想问的内容</h3>-->
<!-- <p>与AI助手开始对话获取智能回答</p>-->
<!-- </div>-->
</div>
<template v-for="(msg, idx) in messages" :key="idx">
<McBubble v-if="msg.role === 'user'" :content="msg.content" :align="'right'"></McBubble>
<McBubble v-else :loading="msg.loading ?? false">
<McMarkdownCard :content="msg.content" :theme="theme"></McMarkdownCard>
</McBubble>
</template>
</div>
</McLayoutContent>
<McLayoutSender>
<McInput :value="inputValue" :maxLength="2000" @submit="onSubmit" showCount></McInput>
</McLayoutSender>
</McLayout>
</div>
</d-modal>
</template>
<script setup>
import { ref, watch,nextTick } from 'vue';
import { Message } from 'vue-devui';
import axios from 'axios';
import {uvdV1Chat} from "@/api/inboundTask/inboundTaskApi";
const messages = ref([]);
const history = ref([]);
const resultInfo = ref(null);
const inputValue = ref('');
const conversationRef = ref(null);
// 组件状态
const visible = ref(false);
const VITE_AI_API_HOST = import.meta.env.VITE_AI_API_HOST;
// 打开弹框时调用接口
const open = async (id) => {
if (!id) return Message.error('缺少result_id参数');
visible.value = true;
resultInfo.value = id
};
const onSubmit = (e) => {
if(e === '') {
return;
}
if(messages.value[messages.value.length-1]?.loading) return;
inputValue.value = '';
messages.value.push({
role: 'user',
content: e,
});
nextTick(() => {
conversationRef.value?.scrollTo({
top: conversationRef.value.scrollHeight,
behavior: 'smooth',
});
});
getAIAnswer(e);
};
const getAIAnswer = async (content) => {
messages.value.push({
role: 'assistant',
content: '',
loading: true,
});
const res = await uvdV1Chat({
"resultInfo": resultInfo.value,
"query": content,
"history": history.value || []
});
let reply = res?.data?.data?.reply || '';
history.value.push({role: "user", content: content});
history.value.push({role: "assistant", content: reply});
messages.value[messages.value.length - 1].content = reply;
messages.value[messages.value.length - 1].loading = false;
nextTick(() => {
conversationRef.value?.scrollTo({
top: conversationRef.value.scrollHeight
});
});
/* 模拟流式数据返回 */
// setTimeout(async () => {
// messages.value.at(-1).loading = false;
// for (let i = 0; i < reply.length;) {
// await new Promise(r => setTimeout(r, 300 * Math.random()));
// messages.value[messages.value.length - 1].content = reply.slice(0, i += Math.random() * 10);
// nextTick(() => {
// conversationRef.value?.scrollTo({
// top: conversationRef.value.scrollHeight
// });
// });
// }
// }, 1000);
};
// 暴露给父组件的方法
defineExpose({
open // 通过ref调用open方法传递resultId
});
// 关闭弹框
const handleClose = () => {
messages.value = [];
history.value = [];
result_id.value = null;
inputValue.value = '';
visible.value = false;
};
</script>
<style lang="scss" scoped>
.log-content {
padding: 24px;
line-height: 1.6;
white-space: pre-wrap; // 保留日志换行
word-break: break-all; // 自动换行长单词
min-height: 200px;
p {
margin: 0;
color: #333;
}
}
.conversation-area,
.welcome-page {
flex: 1;
display: flex;
flex-direction: column;
overflow: auto;
padding: 0 12px;
min-height: 400px;
max-height: 600px;
overflow-y: auto;
}
.conversation-area {
gap: 8px;
}
.welcome-message {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
padding: 32px;
text-align: center;
.welcome-icon {
width: 64px;
height: 64px;
background-color: #e6f4ff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16px;
i {
font-size: 28px;
color: #1677ff;
}
}
.welcome-text {
h3 {
font-size: 18px;
font-weight: 500;
color: #333;
margin-bottom: 8px;
}
p {
font-size: 14px;
color: #666;
}
}
}
.home-title {
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
gap: 20px;
h1 {
color: #191919;
font-family: Huawei Sans;
font-weight: bold;
font-size: 32px;
line-height: 48px;
letter-spacing: 0px;
text-align: center;
}
img {
width: 64px;
//filter: brightness(0);
}
}
.home-detail {
.home-detail-1 {
color: #191919;
font-family: HarmonyOS Sans SC;
font-weight: medium;
font-size: 24px;
line-height: 32px;
letter-spacing: 0px;
text-align: center;
margin-bottom: 24px;
}
.home-detail-2 {
color: #777777;
font-family: HarmonyOS Sans SC;
font-weight: regular;
font-size: 14px;
line-height: 22px;
letter-spacing: 0px;
text-align: center;
}
}
.welcome-page {
//height: 90%;
width: 100%;
flex: 1;
display: flex;
flex-direction: column;
overflow: auto;
padding: 0 12px;
}
.welcome-page {
gap: 16px;
justify-content: center;
}
</style>