ZdyRagList.vue 3.9 KB
<template>
  <div class="chat-container">
    <!-- 聊天消息区域 -->
    <div class="chat-messages" ref="messagesContainer">
      <div v-for="(message, index) in messages" :key="index" :class="['message', message.type]">
        <div class="message-content">
          <div class="message-text">{{ message.text }}</div>
          <div v-if="message.type === 'assistant' && message.similarity" class="message-meta">
            相似度: {{ (message.similarity * 100).toFixed(2) }}%
          </div>
        </div>
      </div>
      <div v-if="loading" class="message assistant">
        <div class="message-content">
          <div class="message-text">思考中...</div>
        </div>
      </div>
    </div>

    <!-- 输入区域 -->
    <div class="chat-input">
      <a-input
        v-model:value="inputMessage"
        placeholder="请输入您的问题..."
        @pressEnter="sendMessage"
        :disabled="loading"
      />
      <a-button
        type="primary"
        @click="sendMessage"
        :loading="loading"
        :disabled="!inputMessage.trim()"
      >
        发送
      </a-button>
    </div>
  </div>
</template>

<script lang="ts" name="zdy-rag-chat" setup>
import { ref, reactive, nextTick } from 'vue';
import { list, sendMessage as apiSendMessage } from './ZdyRag.api';
import { BasicTable, useTable } from '/@/components/Table';
import { useMessage } from '/@/hooks/web/useMessage';

const { createMessage } = useMessage();

// 聊天消息数据
const messages = reactive([
  {
    type: 'assistant',
    text: '您好!我是智能助手,请问有什么可以帮您?',
    similarity: null
  }
]);

const inputMessage = ref('');
const loading = ref(false);
const messagesContainer = ref<HTMLElement>();

// 发送消息
const sendMessage = async () => {
  const text = inputMessage.value.trim();
  if (!text || loading.value) return;

  // 添加用户消息
  messages.push({
    type: 'user',
    text: text,
    similarity: null
  });

  inputMessage.value = '';
  loading.value = true;

  try {
    // 调用API发送消息
    const res = await apiSendMessage({ questionText: text });
    console.log("res....",res)
    if (res?.answer) {
      messages.push({
        type: 'assistant',
        text: res.answer,
        similarity: res.similarity || null
      });
    } else {
      createMessage.error('获取回答失败');
    }
  } catch (error) {
    console.error('发送消息失败:', error);
    createMessage.error('发送消息失败');
  } finally {
    loading.value = false;
    scrollToBottom();
  }
};

// 滚动到底部
const scrollToBottom = () => {
  nextTick(() => {
    if (messagesContainer.value) {
      messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
    }
  });
};
</script>

<style lang="less" scoped>
.chat-container {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 120px);
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
  background-color: #f5f5f5;
  border-radius: 8px;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  margin-bottom: 20px;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.message {
  margin-bottom: 15px;
  display: flex;

  &.user {
    justify-content: flex-end;

    .message-content {
      background-color: #1890ff;
      color: white;
      border-radius: 18px 18px 0 18px;
    }
  }

  &.assistant {
    justify-content: flex-start;

    .message-content {
      background-color: #f0f0f0;
      color: #333;
      border-radius: 18px 18px 18px 0;
    }
  }
}

.message-content {
  max-width: 70%;
  padding: 10px 15px;
  word-wrap: break-word;
}

.message-meta {
  font-size: 12px;
  color: #666;
  margin-top: 5px;
  text-align: right;
}

.chat-input {
  display: flex;
  gap: 10px;

  :deep(.ant-input) {
    flex: 1;
    border-radius: 20px;
    padding: 10px 15px;
  }

  .ant-btn {
    border-radius: 20px;
    padding: 0 20px;
  }
}
</style>