|
@@ -1,20 +1,210 @@
|
|
|
<template>
|
|
|
- <div>
|
|
|
-
|
|
|
- </div>
|
|
|
+ <div style="width:1000px; margin: auto;">
|
|
|
+ <div class="chat-window-wrapper" ref="chatWindowWrapper">
|
|
|
+ <el-card class="chat-window" ref="chatWindow">
|
|
|
+ <div v-for="(message, index) in messages" :key="index" class="message">
|
|
|
+ <img
|
|
|
+ :src="message.sender === 'user' ? require('@/assets/search/soldier.png') : require('@/assets/search/robot.png')"
|
|
|
+ alt="avatar"
|
|
|
+ class="avatar"
|
|
|
+ />
|
|
|
+ <div :class="['bubble', message.sender === 'user' ? 'user-bubble' : message.sender === 'ai' ? 'ai-bubble' : 'system-bubble']">
|
|
|
+ {{ message.content }}
|
|
|
+ <el-button v-if="message.sender === 'system' && requestError" size="mini" type="text" @click="retry(message.oldMsg)" style="margin-left:10px;width:80px"> 重 试</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-show="isWaitingForResponse" class="response-indicator" ref="aiBubble">
|
|
|
+ <img :src="require('@/assets/search/robot.png')" alt="avatar" class="avatar" />
|
|
|
+ <div class="loader"></div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ <div class="input-area">
|
|
|
+ <el-input v-model="inputMessage" type="textarea" placeholder="输入您的消息..." style="margin:5px" :disabled="isWaitingForResponse"
|
|
|
+ @keyup.enter.native="sendMessage(null)"></el-input>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
+
|
|
|
<script>
|
|
|
+import { question } from "@/api/knowledge/search";
|
|
|
export default {
|
|
|
data() {
|
|
|
return {
|
|
|
-
|
|
|
- }
|
|
|
+ inputMessage: "",
|
|
|
+ messages: [],
|
|
|
+ requestError: false,
|
|
|
+ isWaitingForResponse: false,
|
|
|
+ };
|
|
|
},
|
|
|
- created(){
|
|
|
- alert('未完成。。。')
|
|
|
+ methods: {
|
|
|
+ sendMessage(msg) {
|
|
|
+ let inputMessage = msg ? msg :this.inputMessage.trim()
|
|
|
+ if (!inputMessage) return;
|
|
|
+ this.isWaitingForResponse = true;
|
|
|
+
|
|
|
+ if(!msg){
|
|
|
+ this.messages.push({
|
|
|
+ sender: "user",
|
|
|
+ content: inputMessage,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取最后一行的焦点
|
|
|
+ const aiBubbles = this.$refs.aiBubble;
|
|
|
+ console.info(aiBubbles)
|
|
|
+ aiBubbles.focus();
|
|
|
+
|
|
|
+ let oldMsg = inputMessage;
|
|
|
+ this.scrollToBottom();
|
|
|
+ question(inputMessage).then(resp => {
|
|
|
+ this.messages.push({
|
|
|
+ sender: "ai",
|
|
|
+ content: resp.data,
|
|
|
+ });
|
|
|
+ this.scrollToBottom();
|
|
|
+ this.isWaitingForResponse = false;
|
|
|
+ }).catch(error => {
|
|
|
+ console.info(error)
|
|
|
+ this.requestError = true;
|
|
|
+ this.messages.push({
|
|
|
+ sender: "system",
|
|
|
+ content: "系统异常",
|
|
|
+ oldMsg,
|
|
|
+ });
|
|
|
+ this.scrollToBottom();
|
|
|
+ this.isWaitingForResponse = false;
|
|
|
+ })
|
|
|
+ this.inputMessage = "";
|
|
|
+ },
|
|
|
+ retry(msg) {
|
|
|
+ if (this.requestError) {
|
|
|
+ this.requestError = false;
|
|
|
+ this.messages.pop(); // 移除系统提示消息
|
|
|
+ this.sendMessage(msg); // 重新发送
|
|
|
+ }
|
|
|
+ },
|
|
|
+ scrollToBottom() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const chatWindowWrapper = this.$refs.chatWindowWrapper;
|
|
|
+ chatWindowWrapper.scrollTop = chatWindowWrapper.scrollHeight;
|
|
|
+ });
|
|
|
+ },
|
|
|
},
|
|
|
- methods:{
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.chat-window {
|
|
|
+ overflow-y: scroll;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ border: 0px;
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.input-area {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+
|
|
|
+.message {
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.bubble {
|
|
|
+ display: inline-block;
|
|
|
+ padding: 5px 10px;
|
|
|
+ border-radius: 5px;
|
|
|
+ font-family: "Courier New", Courier, monospace;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.5;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ /* flex: 1; */
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+.message {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.avatar {
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.user-bubble {
|
|
|
+ background-color: #45a1ff;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-bubble {
|
|
|
+ background-color: #1a1a1a;
|
|
|
+ color: #45a1ff;
|
|
|
+ border: 1px solid #45a1ff;
|
|
|
+}
|
|
|
+
|
|
|
+.el-input {
|
|
|
+ flex: 1;
|
|
|
+ margin-right: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-input__inner {
|
|
|
+ background-color: #333;
|
|
|
+ border-color: #45a1ff;
|
|
|
+ color: #45a1ff;
|
|
|
+}
|
|
|
+
|
|
|
+.el-input__inner::placeholder {
|
|
|
+ color: #45a1ff;
|
|
|
+}
|
|
|
+
|
|
|
+.el-button {
|
|
|
+ background-color: #45a1ff;
|
|
|
+ border-color: #45a1ff;
|
|
|
+ color: #1a1a1a;
|
|
|
+}
|
|
|
+.el-textarea__inner {
|
|
|
+ background-color: transparent;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+.response-indicator {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.loader {
|
|
|
+ border: 2px solid #45a1ff;
|
|
|
+ border-top: 2px solid #1a1a1a;
|
|
|
+ border-radius: 50%;
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ margin-left: 5px;
|
|
|
+ animation: spin 0.8s linear infinite;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes spin {
|
|
|
+ 0% {
|
|
|
+ transform: rotate(0deg);
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ transform: rotate(360deg);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.chat-window-wrapper {
|
|
|
+ border: 2px solid #45a1ff;
|
|
|
+ height: calc(100vh - 200px);
|
|
|
+ /* max-height: 500px; */
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
|
|
|
- }
|
|
|
+.chat-window {
|
|
|
+ width: 100%;
|
|
|
+ /* min-height: 100%; */
|
|
|
}
|
|
|
-</script>
|
|
|
+</style>
|