【web】 ai助手调整

dev
Wangxin 8 months ago
parent 198868bc3d
commit 480b5f1a8f
  1. 262
      ALOps_sys_fe/alops-ui/src/views/QandA/Aiassistant/index.vue

@ -18,8 +18,8 @@
:class="['message', message.sender]" :class="['message', message.sender]"
> >
<div class="message-content"> <div class="message-content">
<div>{{ message.text }}</div> <div v-html="message.text"></div>
<div class="timestamp">{{ message.time }}</div> <!-- <div class="timestamp">{{ message.time }}</div> -->
</div> </div>
</div> </div>
</div> </div>
@ -73,7 +73,7 @@ export default {
] ]
}; };
},mounted() { },mounted() {
// //
this.scrollToBottom(); this.scrollToBottom();
}, },
methods: { methods: {
@ -86,33 +86,109 @@ export default {
sender: 'customer', sender: 'customer',
time: this.formatTime(new Date()) time: this.formatTime(new Date())
}); });
//
this.scrollToBottom();
let newMessageContent = this.newMessage; let newMessageContent = this.newMessage;
// // autoReply
setTimeout(() => {
this.autoReply(newMessageContent); this.autoReply(newMessageContent);
}, 1000);
this.newMessage = ''; this.newMessage = '';
}, },
async autoReply(userMessage) { async autoReply(userMessage) {
console.log("%c 🇱🇺: autoReply -> userMessage ", "font-size:16px;background-color:#c70b31;color:white;", userMessage) console.log("%c 🇱🇺: autoReply -> userMessage ", "font-size:16px;background-color:#c70b31;color:white;", userMessage)
let replyText = ''; let replyText = '';
// ""
if (userMessage.includes('测试数据')) {
//
setTimeout(() => {
replyText = this.getTestData();
//
const messageIndex = this.messages.length;
this.messages.push({
text: '', //
sender: 'service',
time: this.formatTime(new Date())
});
//
this.typeWriter(messageIndex, replyText);
}, 500);
} else {
// loading
this.isLoading = true;
try {
let res = await knowledgeAsk({question: userMessage }); let res = await knowledgeAsk({question: userMessage });
if (res.code == 200) { if (res.code == 200) {
replyText = res.data.answer; replyText = this.formatResponse(res.data.answer);
}else { } else {
replyText = '很抱歉,暂时无法回答您的问题。您可以尝试其他常见问题或联系客服人员。'; replyText = '很抱歉,暂时无法回答您的问题。您可以尝试其他常见问题或联系客服人员。';
} }
// //
const messageIndex = this.messages.length;
this.messages.push({ this.messages.push({
text: replyText, text: '', //
sender: 'service', sender: 'service',
time: this.formatTime(new Date()) time: this.formatTime(new Date())
}); });
// //
this.typeWriter(messageIndex, replyText);
} finally {
// loading
setTimeout(() => {
this.isLoading = false;
}, 300); //
}
}
},
//
typeWriter(messageIndex, fullText) {
let currentIndex = 0;
//
this.$nextTick(() => {
this.scrollToBottom();
});
const typeInterval = setInterval(() => {
if (currentIndex < fullText.length) {
//
let typeSpeed = 15; // 15/
// HTML
if (fullText[currentIndex] === '<' || (currentIndex > 0 && fullText[currentIndex-1] === '<')) {
// HTML
const tagEndIndex = fullText.indexOf('>', currentIndex);
if (tagEndIndex !== -1) {
//
this.messages[messageIndex].text = fullText.substring(0, tagEndIndex + 1);
currentIndex = tagEndIndex + 1;
} else {
//
this.messages[messageIndex].text = fullText.substring(0, currentIndex + 1);
currentIndex++;
}
} else {
//
this.messages[messageIndex].text = fullText.substring(0, currentIndex + 1);
currentIndex++;
}
//
if (currentIndex % 10 === 0 || currentIndex === fullText.length) {
this.scrollToBottom(); this.scrollToBottom();
}
} else {
//
clearInterval(typeInterval);
//
this.scrollToBottom();
}
}, 15); // 15/
}, },
selectFaq(faq) { selectFaq(faq) {
// //
@ -122,14 +198,16 @@ export default {
time: this.formatTime(new Date()) time: this.formatTime(new Date())
}); });
// // 使
setTimeout(() => { setTimeout(() => {
const messageIndex = this.messages.length;
this.messages.push({ this.messages.push({
text: faq.answer, text: '', //
sender: 'service', sender: 'service',
time: this.formatTime(new Date()) time: this.formatTime(new Date())
}); });
this.scrollToBottom(); // 使
this.typeWriter(messageIndex, faq.answer);
}, 1000); }, 1000);
}, },
scrollToBottom() { scrollToBottom() {
@ -138,6 +216,101 @@ export default {
container.scrollTop = container.scrollHeight; container.scrollTop = container.scrollHeight;
}); });
}, },
// -
scrollToTop() {
this.$nextTick(() => {
const container = this.$refs.messagesContainer;
container.scrollTop = 0;
});
},
// - MarkdownHTML
formatResponse(answer) {
if (!answer) return '';
// Markdown
return this.markdownToHtml(answer);
},
// MarkdownHTML
markdownToHtml(text) {
if (!text) return '';
//
text = text.replace(/^### (.*$)/gm, '<h3>$1</h3>');
text = text.replace(/^## (.*$)/gm, '<h2>$1</h2>');
text = text.replace(/^# (.*$)/gm, '<h1>$1</h1>');
// 线
text = text.replace(/^---$/gm, '<hr>');
//
text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
//
text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
//
text = text.replace(/^> (.*$)/gm, '<blockquote>$1</blockquote>');
//
text = text.replace(/^- (.*$)/gm, '<ul><li>$1</li></ul>');
//
text = text.replace(/<\/li><\/ul>\s*<ul><li>/g, '</li><li>');
//
text = text.replace(/^(\d+)\. (.*$)/gm, '<ol><li>$2</li></ol>');
//
text = text.replace(/<\/li><\/ol>\s*<ol><li>/g, '</li><li>');
//
text = text.replace(/^(?!<h|<ul|<ol|<blockquote|<hr)(.*$)/gm, '<p>$1</p>');
return text;
},
//
getTestData() {
// HTML
return `
<h3>测试数据 - 课程安排信息</h3>
<hr>
<h3>1. 选课时间安排</h3>
<ul>
<li><strong>预选时间</strong>2025年8月26日9:00 8月27日16:00</li>
<li><strong>正选时间</strong>2025年8月29日9:00 8月30日16:00</li>
</ul>
<blockquote><em>说明此为2025-2026学年秋季学期的固定选课窗口期</em></blockquote>
<h3>2. 选课方式与系统登录步骤</h3>
<ul>
<li><strong>选课方式</strong>学生必须通过<strong>电脑端</strong>登录"一网通办"平台</li>
<li>
<strong>系统登录三步法</strong>
<ol>
<li><strong>激活账号</strong>完成账号激活</li>
<li><strong>关注公众号</strong>扫码关注</li>
<li><strong>登录系统</strong>进入平台进行选课</li>
</ol>
</li>
</ul>
<h3>3. 注意事项</h3>
<ul>
<li>
<strong>体育课规则</strong>
<ul>
<li>公选课的体育课<strong>不计入</strong>体育必修课学分</li>
<li>学生毕业前须修<strong>4次体育课</strong></li>
</ul>
</li>
<li>
<strong>课程号前缀要求</strong>
<ul>
<li>校本部学生选课时<strong>课程号必须以"T"开头</strong></li>
</ul>
</li>
</ul>
`;
},
formatTime(date) { formatTime(date) {
const hours = date.getHours().toString().padStart(2, '0'); const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0');
@ -147,6 +320,7 @@ export default {
watch: { watch: {
messages: { messages: {
handler() { handler() {
//
this.scrollToBottom(); this.scrollToBottom();
}, },
deep: true deep: true
@ -202,17 +376,28 @@ export default {
justify-content: flex-end; justify-content: flex-end;
} }
.message-content { .message-content {
max-width: 70%;
padding: 10px 15px; padding: 10px 15px;
border-radius: 4px; border-radius: 4px;
/* 固定最小高度,避免内容变化时高度抖动 */
min-height: 20px;
} }
.message.customer .message-content { .message.customer .message-content {
background-color: #ecf5ff; background:#f5f5f5;
border: 1px solid #d9ecff; border-radius: 26px;
font-family: PingFang SC;
font-size: 16px;
font-weight: 400;
justify-self: end;
line-height: 28px;
max-width: 100%;
padding: 10px 20px;
white-space: pre-wrap;
word-break: break-all;
} }
.message.service .message-content { .message.service .message-content {
background-color: #f4f4f5; background-color: transparent; /* 移除背景色 */
border: 1px solid #e9e9eb; border: none; /* 移除边框 */
width: 100%; /* 设置宽度为100% */
} }
.chat-input { .chat-input {
padding: 15px; padding: 15px;
@ -238,4 +423,43 @@ export default {
margin-top: 5px; margin-top: 5px;
text-align: right; text-align: right;
} }
/* Loading样式 */
.loading-indicator {
display: flex;
justify-content: flex-start;
padding: 10px 0;
}
.loading-dots {
display: flex;
align-items: center;
gap: 4px;
background-color: #f4f4f5;
padding: 8px 16px;
border-radius: 4px;
border: 1px solid #e9e9eb;
}
.loading-dots .dot {
width: 8px;
height: 8px;
background-color: #409EFF;
border-radius: 50%;
animation: loading 1.4s infinite ease-in-out both;
}
.loading-dots .dot:nth-child(1) {
animation-delay: -0.32s;
}
.loading-dots .dot:nth-child(2) {
animation-delay: -0.16s;
}
@keyframes loading {
0%, 80%, 100% {
transform: scale(0);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
}
</style> </style>
Loading…
Cancel
Save