Просмотр исходного кода

首页会话功能弹窗组件化

bobo04052021@163.com 2 недель назад
Родитель
Сommit
453526dc95
2 измененных файлов с 910 добавлено и 864 удалено
  1. 905 0
      src/layouts/default/sider/Aichat.vue
  2. 5 864
      src/layouts/default/sider/bottomSider2.vue

+ 905 - 0
src/layouts/default/sider/Aichat.vue

@@ -0,0 +1,905 @@
+<template>
+  <div>
+    <transition name="fade">
+      <div v-if="visible" class="dialog-overlay">
+        <!-- 左侧折叠区域 -->
+        <div class="left-side" :class="{ collapsed: isFold }" id="leftSide">
+          <div
+            class="addBtn"
+            :style="{
+              backgroundImage: `url(${isFold ? '/src/assets/images/vent/home/add.svg' : ''})`,
+              backgroundColor: isFold ? '' : '#2cb6ff',
+              width: isFold ? '20px' : 'auto',
+            }"
+            @click="addNew"
+          >
+            <span
+              class="btn-text-bg"
+              :style="{
+                backgroundImage: `url(${!isFold ? '/src/assets/images/vent/home/addB.svg' : ''})`,
+              }"
+            ></span>
+            <span v-if="!isFold" class="btn-text">添加新对话</span>
+          </div>
+          <div class="divider0"></div>
+          <div
+            v-if="isFold"
+            class="historyBtn"
+            :style="{ backgroundImage: `url(${isFold ? '/src/assets/images/vent/home/history.svg' : '/src/assets/images/vent/home/history.svg'})` }"
+            @click="addNew"
+          ></div>
+          <div v-else class="historyBtn1">
+            <span
+              class="btn-text-bg"
+              :style="{
+                backgroundImage: `url(${!isFold ? '/src/assets/images/vent/home/history.svg' : ''})`,
+              }"
+            ></span>
+            <span v-if="!isFold" class="btn-text">历史对话</span>
+            <a-list style="width: 110px" :split="false" :data-source="historySessions" :scroll="200" class="custom-list">
+              <template #renderItem="{ item }">
+                <a-list-item
+                  :style="{
+                    padding: '8px 10px 0 8px',
+                    color: '#5e7081',
+                    fontSize: '10px',
+                    position: 'relative', // 新增定位
+                  }"
+                  @click="sessionsHistory(item.id)"
+                >
+                  <!-- 新增flex布局容器 -->
+                  <div style="display: flex; justify-content: space-between; width: 100%">
+                    <div v-if="editingId !== item.id" class="text-container">
+                      <span class="edit-text">{{ item.title || '新会话' }}</span>
+                      <edit-outlined class="edit-icon" @click="startEditing(item)" />
+                    </div>
+
+                    <!-- 输入框 -->
+                    <a-input
+                      size="small"
+                      v-else
+                      v-model:value="editText"
+                      v-focus
+                      @blur="handleSave(item)"
+                      @keyup.enter="handleSave(item)"
+                      class="edit-input"
+                    />
+                  </div>
+                </a-list-item>
+              </template>
+            </a-list>
+          </div>
+          <div
+            class="foldBtn"
+            :style="{ backgroundImage: `url(${isFold ? '/src/assets/images/vent/home/Fold.svg' : '/src/assets/images/vent/home/unfold.svg'})` }"
+            @click="fold"
+          ></div>
+        </div>
+        <!-- 右侧对话框 -->
+        <div class="right-side">
+          <div class="input-content">
+            <!-- 对话区域 -->
+            <div class="dialog-area">
+              <div v-for="message in sortedMessages" :key="message.id" :class="['message-item', message.type]">
+                <!-- 用户提问样式 -->
+                <div v-if="message.type === 'user'" class="ask-message">
+                  <span>{{ message.content }}</span>
+                </div>
+
+                <!-- 系统回答样式 -->
+                <div v-else class="system-message">
+                  <div class="answerIcon"></div>
+                  <div class="answer-message">
+                    <div v-if="message.Origintype === 'thinking'">
+                      <span :id="'thinking-' + message.id" class="thinking-text" v-html="formatMessage(message.content)"></span>
+                    </div>
+                    <div v-if="message.Origintype1 === 'text'">
+                      <span :id="'text-' + message.id" class="answer-text" v-html="formatMessage(message.content1)"></span>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <!-- 文本输入区域 -->
+            <div v-if="spinning" class="thinking-area">
+              <span style="color: #fff">思考中···</span>
+              <a-spin :spinning="spinning"></a-spin>
+            </div>
+            <div class="input-area">
+              <textarea v-model="inputText" placeholder="请输入你的问题"> </textarea>
+              <!-- 底部操作栏 -->
+              <div class="action-bar">
+                <!-- 左侧深度思考按钮 -->
+                <div class="think-btn" :class="{ active: isThinking }" @click="toggleThinking"> <span>深度思考</span> </div>
+
+                <!-- 右侧操作按钮 -->
+                <div class="right-actions">
+                  <label class="upload-btn">
+                    <div class="send-file"></div>
+                    <span class="divider"> | </span>
+                    <div class="send-img"></div>
+                    <div class="send-btn" @click="handleSend"></div>
+                  </label>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </transition>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, onMounted, unref, nextTick, computed } from 'vue';
+import { useUserStore } from '/@/store/modules/user';
+import { EditOutlined } from '@ant-design/icons-vue';
+// 响应式变量声明
+const dialogVisible = ref(false);
+const isFold = ref(false); // 是否折叠
+const inputText = ref(''); // 输入框内容
+const historySessions = ref([]); // 消会话历史
+const spinning = ref(false); // 加载状态
+const systemMessage = ref(''); // 系统返回信息
+const session_id = ref(''); // 会话id
+const hasCreated = ref(false); // 标志位,防止重复调用create接口
+const hasAdd = ref(false); // 标志位,防止重复调用create接口
+const userStore = useUserStore(); //获取用户信息
+const editingId = ref<number | null>(null);
+const editText = ref('');
+const isThinking = ref(false);
+interface ListItem {
+  id: number;
+  title?: string;
+}
+defineProps({
+  visible: {
+    type: Boolean,
+    required: true,
+  },
+});
+let userId = unref(userStore.getUserInfo).id;
+// const userId = ref(0);
+type MessageItem = {
+  id: string; // 唯一标识时间戳
+  type: 'user' | 'system';
+  content?: string;
+  content1?: string;
+  Origintype?: string;
+  Origintype1?: string;
+  timestamp: number; // 排序依据
+};
+const messageList = ref<MessageItem[]>([]);
+const sortedMessages = computed(() => {
+  return messageList.value.sort((a, b) => a.timestamp - b.timestamp);
+});
+const vFocus = {
+  mounted: (el: HTMLElement) => el.querySelector('input')?.focus(),
+};
+const scrollToBottom = () => {
+  const dialogArea = document.querySelector('.dialog-area');
+  if (dialogArea) {
+    dialogArea.scrollTop = dialogArea.scrollHeight;
+  }
+};
+
+// const openMenu = () => {
+//   dialogVisible.value = props.modelValue;
+//   // console.log(props.dialogVisible, 'ssssssssss');
+//   if (dialogVisible.value) {
+//     // addNew();
+//     hasCreated.value = true;
+//   }
+// };
+const fold = () => {
+  isFold.value = !isFold.value;
+  if (!isFold.value) {
+    sessionsHistoryList();
+  }
+};
+//启用深度思考
+const toggleThinking = () => {
+  isThinking.value = !isThinking.value;
+};
+//创建新对话
+async function addNew() {
+  hasAdd.value = !hasAdd.value;
+  const params = {
+    user_id: userId,
+  };
+  let response = await fetch('http://182.92.126.35:6005/sessions/create', {
+    method: 'post',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+    body: JSON.stringify(params),
+  });
+  const data = await response.json();
+  session_id.value = data.id;
+  messageList.value = [];
+}
+//编辑标题
+const startEditing = (item: ListItem) => {
+  editingId.value = item.id;
+  editText.value = item.title || '';
+};
+
+// 保存修改
+const handleSave = async (item: ListItem) => {
+  const params = {
+    chat_session_id: item.id,
+    new_title: editText.value,
+  };
+  try {
+    let response = await fetch('http://182.92.126.35:6005/sessions/change_title', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify(params),
+    });
+    if (!response.ok) {
+      throw new Error('Network response was not ok');
+    }
+    item.title = editText.value;
+  } catch (error) {
+    console.error('保存失败:', error);
+  }
+  editingId.value = null;
+};
+//获取消息列表
+async function handleSend() {
+  if (session_id.value === '') {
+    await addNew();
+    createSessionTitle({ session_id: session_id.value, title: inputText.value });
+    sendMessage1();
+  } else {
+    createSessionTitle({ session_id: session_id.value, title: inputText.value });
+    sendMessage1();
+  }
+}
+//发送消息
+async function sendMessage() {
+  spinning.value = true;
+  // 添加用户消息
+  messageList.value.push({
+    id: `user_${Date.now()}`,
+    type: 'user',
+    content: inputText.value,
+    timestamp: Date.now(),
+  });
+  const params = {
+    chat_session_id: session_id.value,
+    prompt: inputText.value,
+    ref_file_ids: [],
+    thinking_enabled: false,
+  };
+  inputText.value = ''; // 清空输入框
+  //将用户输入的内容发送到后端
+  try {
+    // 将用户输入的内容发送到后端
+    let response = await fetch('http://182.92.126.35:6005/chat', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify(params),
+    });
+
+    if (!response.ok) {
+      throw new Error('Network response was not ok');
+    }
+
+    const data = await response.json();
+    const assistantReply = data.reply.content; // 获取助手回复
+    // formatMessage(assistantReply);
+    systemMessage.value = assistantReply;
+
+    // 添加系统回答
+    messageList.value.push({
+      id: `system_${Date.now()}`,
+      type: 'system',
+      content: systemMessage.value,
+      timestamp: Date.now(),
+    });
+  } catch (error) {
+    // 请求失败时设置系统消息为"服务器异常"
+    systemMessage.value = '服务器异常';
+    console.error('请求失败:', error);
+  } finally {
+    spinning.value = false; // 无论请求成功与否,都停止加载指示器
+  }
+}
+//发送消息  流式响应
+const sendMessage1 = async () => {
+  spinning.value = true; // 开始加载
+  messageList.value.push({
+    id: `user_${Date.now()}`,
+    type: 'user',
+    content: inputText.value,
+    timestamp: Date.now(),
+  });
+  // 构造请求参数
+  const params = {
+    chat_session_id: session_id.value, // 替换为实际的会话 ID
+    prompt: inputText.value,
+    ref_file_ids: [],
+    thinking_enabled: isThinking.value,
+  };
+  inputText.value = ''; // 清空输入框
+  try {
+    // 发送 POST 请求
+    const response = await fetch('http://182.92.126.35:6005/chat_stream', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify(params),
+    });
+
+    // 检查响应是否成功
+    if (!response.ok) {
+      throw new Error('Network response was not ok');
+    }
+
+    // 获取可读流
+    const reader = response.body.getReader();
+
+    // 创建一条新的消息对象
+    const newMessage = {
+      id: `response_${Date.now()}`,
+      type: 'response', // 消息类型
+      content: '',
+      content1: '',
+      Origintype: '',
+      timestamp: Date.now(), // 时间戳用来排序
+    };
+
+    // 将新消息添加到消息列表
+    messageList.value.push(newMessage);
+
+    // 读取流式数据
+    while (true) {
+      const { done, value } = await reader.read();
+      if (done) {
+        console.log('Stream complete');
+        break;
+      }
+
+      // 将流数据转换为字符串
+      const chunk = new TextDecoder().decode(value);
+      console.log('Received chunk:', chunk);
+
+      // 使用正则表达式匹配完整的 JSON 对象
+      const jsonRegex = /{.*?}/g;
+      const matches = chunk.match(jsonRegex);
+      if (matches) {
+        matches.forEach((match) => {
+          try {
+            const data = JSON.parse(match);
+            console.log(data.type, '数据类型11111111111111111');
+            if (data.type === 'thinking') {
+              // 找到当前消息对象并更新 content
+              const targetMessage = messageList.value.find((msg) => msg.id === newMessage.id);
+              if (targetMessage) {
+                targetMessage.content += data.content; // 追加内容
+                targetMessage.Origintype = data.type;
+                scrollToBottom();
+              }
+            }
+            if (data.type === 'text') {
+              // 找到当前消息对象并更新 content
+              const targetMessage = messageList.value.find((msg) => msg.id === newMessage.id);
+              if (targetMessage) {
+                targetMessage.content1 += data.content; // 追加内容
+                targetMessage.Origintype1 = data.type;
+                scrollToBottom();
+              }
+            }
+          } catch (error) {
+            console.error('Failed to parse JSON:', error);
+          }
+        });
+      }
+    }
+  } catch (error) {
+    // 请求失败时设置系统消息
+    if (!response || !response.ok) {
+      systemMessage.value = '服务器异常';
+      messageList.value.push({
+        id: `system_${Date.now()}`,
+        type: 'system',
+        content: systemMessage.value,
+        Origintype: 'text',
+        timestamp: Date.now(),
+      });
+      console.error('请求失败:', error);
+    }
+  } finally {
+    spinning.value = false; // 停止加载
+  }
+};
+//创建标题
+async function createSessionTitle({ session_id, title }) {
+  const params = {
+    chat_session_id: session_id,
+    prompt: title,
+  };
+  let response = await fetch('http://182.92.126.35:6005/sessions/title', {
+    method: 'post',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+    body: JSON.stringify(params),
+  });
+  const data = await response.json();
+}
+//获取会话历史
+async function sessionsHistoryList() {
+  const params = {
+    user_id: userId,
+  };
+  let response = await fetch(`http://182.92.126.35:6005/sessions`, {
+    method: 'post',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+    body: JSON.stringify(params),
+  });
+  const data = await response.json();
+  historySessions.value = data.chat_sessions;
+}
+//获取具体会话记录
+async function sessionsHistory(id: string) {
+  let response = await fetch(`http://182.92.126.35:6005/sessions/history_chat/?chat_session_id=${id}`, {
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+  });
+  const data = await response.json();
+  if (data.chat_messages.length > 0) {
+    messageList.value = [];
+    data.chat_messages.forEach((item: any) => {
+      // role== user 用户提问
+      if (item.role === 'user') {
+        messageList.value.push({
+          id: `user_${Date.now()}`,
+          type: 'user',
+          content: item.content,
+          timestamp: Date.now(),
+        });
+      } else if (item.role === 'assistant') {
+        // role== assistant 机器回答
+        if (item.thinking_enabled) {
+          messageList.value.push({
+            id: `system_${Date.now()}_thinking`,
+            type: 'system',
+            content: item.thinking_content,
+            Origintype: 'thinking',
+            timestamp: Date.now(),
+          });
+          messageList.value.push({
+            id: `system_${Date.now()}_text`,
+            type: 'system',
+            content1: item.content,
+            Origintype1: 'text',
+            timestamp: Date.now(),
+          });
+        } else {
+          messageList.value.push({
+            id: `system_${Date.now()}`,
+            type: 'system',
+            content: item.content,
+            timestamp: Date.now(),
+          });
+        }
+
+        console.log(item.content);
+      }
+    });
+  }
+}
+//格式化消息
+function formatMessage(text: string) {
+  let formatted = text
+    // 处理换行
+    .replace(/\n\n/g, '<br>')
+    .replace(/\n###/g, '<br> ')
+    .replace(/###/g, '')
+    .replace(/---/g, '')
+    // 处理粗体
+    .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
+    // 处理斜体
+    .replace(/\*(.*?)\*/g, '<em>$1</em>')
+    // 处理行内代码
+    .replace(/`([^`]+)`/g, '<code>$1</code>');
+  return formatted;
+}
+const emit = defineEmits(['update:modelValue']);
+
+const close = () => {
+  emit('update:modelValue', false);
+};
+
+// 初始化按钮定位
+onMounted(() => {
+  sessionsHistoryList();
+  console.log('ssssssssss');
+});
+</script>
+
+<style lang="less" scoped>
+@keyframes menuShow {
+  0% {
+    width: 0;
+    height: 0;
+  }
+  100% {
+    width: 480px;
+    height: 100vh;
+  }
+}
+.custom-list {
+  height: 360px;
+  overflow-y: auto;
+}
+/* 穿透组件作用域 */
+::v-deep .custom-list {
+  scrollbar-width: thin;
+  scrollbar-color: #1890ff #f0f0f0;
+  &::-webkit-scrollbar {
+    width: 4px;
+    height: 6px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #1890ff;
+    border-radius: 4px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: #f0f0f0;
+    border-radius: 4px;
+  }
+}
+::v-deep .zxm-list-items {
+  color: #1890ff;
+}
+::v-deep .zxm-list-item:hover {
+  text-decoration: underline;
+  color: #1890ff !important;
+}
+.text-container {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  overflow: hidden;
+}
+
+.text-ellipsis {
+  flex: 1;
+}
+.edit-text {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  min-width: 0;
+}
+.edit-icon {
+  flex-shrink: 0;
+  cursor: pointer;
+  margin-left: auto;
+}
+.edit-input {
+  font-size: 10px;
+}
+.trigger-button {
+  position: fixed;
+  bottom: 10px;
+  right: 10px;
+  z-index: 1000000;
+  .icon {
+    width: 60px;
+    height: 60px;
+    position: relative;
+    background-image: url('/@/assets/images/vent/home/wakeBtn.png');
+    background-position: center;
+    background-size: 100% 100%;
+  }
+}
+.dialog-overlay {
+  width: 32%;
+  height: 55%;
+  z-index: 999;
+  display: flex;
+  position: fixed;
+  right: 90px;
+  bottom: 20px;
+  box-shadow: 0 0 3px 3px #1074c1;
+  background-color: #09172c;
+}
+
+/* 遮罩层淡入淡出 */
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.3s;
+}
+.fade-enter-from,
+.fade-leave-to {
+  opacity: 0;
+}
+
+/* 弹窗缩放动画 */
+.scale-enter-active,
+.scale-leave-active {
+  transition: all 0.3s ease;
+}
+.scale-enter-from {
+  transform: scale(0.5) translate(-50%, -50%);
+  opacity: 0;
+}
+.scale-leave-to {
+  transform: scale(1.2) translate(-50%, -50%);
+  opacity: 0;
+}
+
+.left-side {
+  background: #0c2842;
+  transition: width 0.5s ease; /* 平滑过渡动画 */
+  width: 120px; /* 展开时宽度 */
+  position: relative; /* 用于按钮定位 */
+}
+.left-side.collapsed {
+  width: 40px; /* 折叠时宽度 */
+}
+
+.addBtn {
+  height: 30px;
+  position: absolute;
+  background-size: 100% 100%;
+  background-position: center;
+  padding: 2px;
+  right: 10px;
+  top: 10px;
+  left: 10px;
+  align-items: center;
+  border-radius: 3px;
+  cursor: pointer;
+}
+.btn-text-bg {
+  width: 14px;
+  height: 14px;
+  position: absolute;
+  background-size: 100% 100%;
+  right: 10px;
+  top: 9px;
+  left: 10px;
+  bottom: 10px;
+}
+.btn-text {
+  margin-left: 3px;
+  font-size: 12px;
+  color: #fff;
+  white-space: nowrap;
+  margin-left: 30px;
+  line-height: 26px;
+}
+.historyBtn {
+  width: 20px;
+  height: 20px;
+  position: absolute;
+  background-size: 100% 100%;
+  background-position: center;
+  padding: 2px;
+  right: 10px;
+  top: 100px;
+}
+.historyBtn1 {
+  width: 20px;
+  height: 20px;
+  position: absolute;
+  background-size: 100% 100%;
+  background-position: center;
+  left: 3px;
+  top: 80px;
+}
+.divider0 {
+  border-bottom: 1px solid #1074c1;
+  width: auto;
+  margin: 0 10px;
+  height: 13%;
+  display: block;
+  background: transparent;
+}
+.foldBtn {
+  width: 20px;
+  height: 20px;
+  position: absolute;
+  background-size: 100% 100%;
+  background-position: center;
+  padding: 2px;
+  right: 10px;
+  bottom: 10px;
+  cursor: pointer;
+}
+
+.right-side {
+  flex: 1; /* 占据剩余空间 */
+  background: #09172c;
+}
+
+.input-content {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-end; /* 内容底部对齐 */
+  height: 100%;
+  padding: 20px; /* 统一内边距 */
+}
+.ask-message {
+  align-self: flex-end;
+  float: right;
+  max-width: 70%;
+  padding: 10px;
+  margin: 10px;
+  border-radius: 5px;
+  color: #fff;
+  background: #0c2842;
+  align-self: flex-end; /* 右侧对齐‌:ml-citation{ref="2" data="citationList"} */
+}
+.answer {
+  display: flex;
+  flex-direction: row;
+}
+.answerIcon {
+  flex-shrink: 0;
+  margin-top: 10px;
+  width: 35px;
+  height: 35px;
+  background-image: url('/@/assets/images/vent/home/answerIcon.svg');
+  background-size: 100% 100%;
+}
+.answer-message {
+  float: left;
+  padding: 10px;
+  margin: 10px;
+  border-radius: 5px;
+  background: #0c2842;
+}
+.thinking-text {
+  color: gray;
+  font-size: 12px;
+}
+.answer-text {
+  color: #fff;
+}
+/** 系统返回信息**/
+.system-message {
+  display: flex;
+  flex-direction: row;
+  align-self: flex-start;
+  width: 100%;
+  padding: 12px;
+  display: flex;
+}
+.answerIcon {
+  margin-top: 10px;
+  width: 35px;
+  height: 35px;
+  background-image: url('/@/assets/images/vent/home/answerIcon.svg');
+  background-size: 100% 100%;
+}
+.think-area {
+  color: #7979799f;
+}
+.answer-area {
+  color: #fff;
+}
+.dialog-area {
+  flex: 1; /* 占据剩余空间 */
+  gap: 50px; /* 消息块间隔统一控制 */
+  overflow-y: auto; /* 垂直滚动条 */
+  margin-bottom: 10px;
+}
+.loading-wrapper,
+.content-wrapper {
+  min-height: 40px;
+}
+.message-item.user {
+  margin-bottom: 50px;
+}
+.input-area {
+  background-color: #043256 !important;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+textarea {
+  background-color: #043256 !important;
+  width: 100%;
+  height: 40px;
+  border: none;
+  resize: none;
+  outline: none;
+  overflow: hidden;
+  padding: 10px; /* 统一内边距 */
+  color: #fff;
+}
+
+.action-bar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 8px 16px;
+}
+
+.think-btn {
+  border: 1px solid #ccc;
+  width: 120px;
+  height: 20px;
+  line-height: 20px;
+  text-align: center;
+  border-radius: 50px;
+  cursor: pointer;
+  background: white;
+  transition: background 0.3s;
+}
+
+.think-btn.active {
+  background: #1890ff;
+  color: white;
+  border-color: #1890ff;
+}
+.right-actions {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.upload-btn {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+.upload-btn {
+  float: right;
+  display: flex;
+  cursor: pointer;
+  padding: 6px 12px;
+}
+
+.divider {
+  color: #ccc;
+  font-weight: 300;
+  margin: 0 10px;
+}
+
+.send-file {
+  width: 20px;
+  height: 20px;
+  background-image: url('/@/assets/images/vent/home/sendFile.svg');
+  background-size: 100% 100%;
+  border-radius: 4px;
+  cursor: pointer;
+}
+.send-img {
+  width: 20px;
+  height: 20px;
+  background-image: url('/@/assets/images/vent/home/sendImg.svg');
+  background-size: 100% 100%;
+  border-radius: 4px;
+  cursor: pointer;
+}
+.send-btn {
+  width: 20px;
+  height: 20px;
+  margin-left: 10px;
+  margin-right: 10px;
+  background-color: #1074c1;
+  background-image: url('/@/assets/images/vent/home/send.svg');
+  background-position: center;
+  background-size: 100% 100%;
+  border-radius: 2px;
+  cursor: pointer;
+}
+</style>

+ 5 - 864
src/layouts/default/sider/bottomSider2.vue

@@ -1,588 +1,22 @@
 <template>
   <div>
     <div class="trigger-button">
-      <div class="icon" @click="openMenu"></div>
+      <div class="icon" @click="openMenu" :style="{ zIndex: 1000 }"></div>
+      <Aichat :visible="dialogVisible" />
     </div>
-    <transition name="fade">
-      <div v-if="dialogVisible" class="dialog-overlay">
-        <!-- 左侧折叠区域 -->
-        <div class="left-side" :class="{ collapsed: isFold }" id="leftSide">
-          <div
-            class="addBtn"
-            :style="{
-              backgroundImage: `url(${isFold ? '/src/assets/images/vent/home/add.svg' : ''})`,
-              backgroundColor: isFold ? '' : '#2cb6ff',
-              width: isFold ? '20px' : 'auto',
-            }"
-            @click="addNew"
-          >
-            <span
-              class="btn-text-bg"
-              :style="{
-                backgroundImage: `url(${!isFold ? '/src/assets/images/vent/home/addB.svg' : ''})`,
-              }"
-            ></span>
-            <span v-if="!isFold" class="btn-text">添加新对话</span>
-          </div>
-          <div class="divider0"></div>
-          <div
-            v-if="isFold"
-            class="historyBtn"
-            :style="{ backgroundImage: `url(${isFold ? '/src/assets/images/vent/home/history.svg' : '/src/assets/images/vent/home/history.svg'})` }"
-            @click="addNew"
-          ></div>
-          <div v-else class="historyBtn1">
-            <span
-              class="btn-text-bg"
-              :style="{
-                backgroundImage: `url(${!isFold ? '/src/assets/images/vent/home/history.svg' : ''})`,
-              }"
-            ></span>
-            <span v-if="!isFold" class="btn-text">历史对话</span>
-            <a-list style="width: 110px" :split="false" :data-source="historySessions" :scroll="200" class="custom-list">
-              <template #renderItem="{ item }">
-                <a-list-item
-                  :style="{
-                    padding: '8px 10px 0 8px',
-                    color: '#5e7081',
-                    fontSize: '10px',
-                    position: 'relative', // 新增定位
-                  }"
-                  @click="sessionsHistory(item.id)"
-                >
-                  <!-- 新增flex布局容器 -->
-                  <div style="display: flex; justify-content: space-between; width: 100%">
-                    <div v-if="editingId !== item.id" class="text-container">
-                      <span class="edit-text">{{ item.title || '新会话' }}</span>
-                      <edit-outlined class="edit-icon" @click="startEditing(item)" />
-                    </div>
-
-                    <!-- 输入框 -->
-                    <a-input
-                      size="small"
-                      v-else
-                      v-model:value="editText"
-                      v-focus
-                      @blur="handleSave(item)"
-                      @keyup.enter="handleSave(item)"
-                      class="edit-input"
-                    />
-                  </div>
-                </a-list-item>
-              </template>
-            </a-list>
-          </div>
-          <div
-            class="foldBtn"
-            :style="{ backgroundImage: `url(${isFold ? '/src/assets/images/vent/home/Fold.svg' : '/src/assets/images/vent/home/unfold.svg'})` }"
-            @click="fold"
-          ></div>
-        </div>
-        <!-- 右侧对话框 -->
-        <div class="right-side">
-          <div class="input-content">
-            <!-- 对话区域 -->
-            <div class="dialog-area">
-              <div v-for="message in sortedMessages" :key="message.id" :class="['message-item', message.type]">
-                <!-- 用户提问样式 -->
-                <div v-if="message.type === 'user'" class="ask-message">
-                  <span>{{ message.content }}</span>
-                </div>
-
-                <!-- 系统回答样式 -->
-                <div v-else class="system-message">
-                  <div class="answerIcon"></div>
-                  <div class="answer-message">
-                    <div v-if="message.Origintype === 'thinking'">
-                      <span :id="'thinking-' + message.id" class="thinking-text" v-html="formatMessage(message.content)"></span>
-                    </div>
-                    <div v-if="message.Origintype1 === 'text'">
-                      <span :id="'text-' + message.id" class="answer-text" v-html="formatMessage(message.content1)"></span>
-                    </div>
-                  </div>
-                </div>
-              </div>
-            </div>
-            <!-- 文本输入区域 -->
-            <div v-if="spinning" class="thinking-area">
-              <span style="color: #fff">思考中···</span>
-              <a-spin :spinning="spinning"></a-spin>
-            </div>
-            <div class="input-area">
-              <textarea v-model="inputText" placeholder="请输入你的问题"> </textarea>
-              <!-- 底部操作栏 -->
-              <div class="action-bar">
-                <!-- 左侧深度思考按钮 -->
-                <div class="think-btn" :class="{ active: isThinking }" @click="toggleThinking"> <span>深度思考</span> </div>
-
-                <!-- 右侧操作按钮 -->
-                <div class="right-actions">
-                  <label class="upload-btn">
-                    <div class="send-file"></div>
-                    <span class="divider"> | </span>
-                    <div class="send-img"></div>
-                    <div class="send-btn" @click="handleSend"></div>
-                  </label>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </transition>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted, unref, nextTick, computed } from 'vue';
-import { useUserStore } from '/@/store/modules/user';
-import { EditOutlined } from '@ant-design/icons-vue';
-// 响应式变量声明
+import { ref } from 'vue';
+import Aichat from './Aichat.vue';
 const dialogVisible = ref(false);
-const isFold = ref(false); // 是否折叠
-const inputText = ref(''); // 输入框内容
-const historySessions = ref([]); // 消会话历史
-const spinning = ref(false); // 加载状态
-const systemMessage = ref(''); // 系统返回信息
-const session_id = ref(''); // 会话id
-const hasCreated = ref(false); // 标志位,防止重复调用create接口
-const hasAdd = ref(false); // 标志位,防止重复调用create接口
-const userStore = useUserStore(); //获取用户信息
-const editingId = ref<number | null>(null);
-const editText = ref('');
-const isThinking = ref(false);
-interface ListItem {
-  id: number;
-  title?: string;
-}
-let userId = unref(userStore.getUserInfo).id;
-// const userId = ref(0);
-type MessageItem = {
-  id: string; // 唯一标识时间戳
-  type: 'user' | 'system';
-  content?: string;
-  content1?: string;
-  Origintype?: string;
-  Origintype1?: string;
-  timestamp: number; // 排序依据
-};
-const messageList = ref<MessageItem[]>([]);
-const sortedMessages = computed(() => {
-  return messageList.value.sort((a, b) => a.timestamp - b.timestamp);
-});
-const vFocus = {
-  mounted: (el: HTMLElement) => el.querySelector('input')?.focus(),
-};
-const scrollToBottom = () => {
-  const dialogArea = document.querySelector('.dialog-area');
-  if (dialogArea) {
-    dialogArea.scrollTop = dialogArea.scrollHeight;
-  }
-};
-
 const openMenu = () => {
   dialogVisible.value = !dialogVisible.value;
-  if (dialogVisible.value) {
-    // addNew();
-    hasCreated.value = true;
-  }
-};
-const fold = () => {
-  isFold.value = !isFold.value;
-  if (!isFold.value) {
-    sessionsHistoryList();
-  }
-};
-//启用深度思考
-const toggleThinking = () => {
-  isThinking.value = !isThinking.value;
-};
-//创建新对话
-async function addNew() {
-  hasAdd.value = !hasAdd.value;
-  const params = {
-    user_id: userId,
-  };
-  let response = await fetch('http://182.92.126.35:6005/sessions/create', {
-    method: 'post',
-    headers: {
-      'Content-Type': 'application/json',
-    },
-    body: JSON.stringify(params),
-  });
-  const data = await response.json();
-  session_id.value = data.id;
-  messageList.value = [];
-}
-//编辑标题
-const startEditing = (item: ListItem) => {
-  editingId.value = item.id;
-  editText.value = item.title || '';
-};
-
-// 保存修改
-const handleSave = async (item: ListItem) => {
-  const params = {
-    chat_session_id: item.id,
-    new_title: editText.value,
-  };
-  try {
-    let response = await fetch('http://182.92.126.35:6005/sessions/change_title', {
-      method: 'POST',
-      headers: {
-        'Content-Type': 'application/json',
-      },
-      body: JSON.stringify(params),
-    });
-    if (!response.ok) {
-      throw new Error('Network response was not ok');
-    }
-    item.title = editText.value;
-  } catch (error) {
-    console.error('保存失败:', error);
-  }
-  editingId.value = null;
-};
-//获取消息列表
-async function handleSend() {
-  if (session_id.value === '') {
-    await addNew();
-    createSessionTitle({ session_id: session_id.value, title: inputText.value });
-    sendMessage1();
-  } else {
-    createSessionTitle({ session_id: session_id.value, title: inputText.value });
-    sendMessage1();
-  }
-}
-//发送消息
-async function sendMessage() {
-  spinning.value = true;
-  // 添加用户消息
-  messageList.value.push({
-    id: `user_${Date.now()}`,
-    type: 'user',
-    content: inputText.value,
-    timestamp: Date.now(),
-  });
-  const params = {
-    chat_session_id: session_id.value,
-    prompt: inputText.value,
-    ref_file_ids: [],
-    thinking_enabled: false,
-  };
-  inputText.value = ''; // 清空输入框
-  //将用户输入的内容发送到后端
-  try {
-    // 将用户输入的内容发送到后端
-    let response = await fetch('http://182.92.126.35:6005/chat', {
-      method: 'POST',
-      headers: {
-        'Content-Type': 'application/json',
-      },
-      body: JSON.stringify(params),
-    });
-
-    if (!response.ok) {
-      throw new Error('Network response was not ok');
-    }
-
-    const data = await response.json();
-    const assistantReply = data.reply.content; // 获取助手回复
-    // formatMessage(assistantReply);
-    systemMessage.value = assistantReply;
-
-    // 添加系统回答
-    messageList.value.push({
-      id: `system_${Date.now()}`,
-      type: 'system',
-      content: systemMessage.value,
-      timestamp: Date.now(),
-    });
-  } catch (error) {
-    // 请求失败时设置系统消息为"服务器异常"
-    systemMessage.value = '服务器异常';
-    console.error('请求失败:', error);
-  } finally {
-    spinning.value = false; // 无论请求成功与否,都停止加载指示器
-  }
-}
-//发送消息  流式响应
-const sendMessage1 = async () => {
-  spinning.value = true; // 开始加载
-  messageList.value.push({
-    id: `user_${Date.now()}`,
-    type: 'user',
-    content: inputText.value,
-    timestamp: Date.now(),
-  });
-  // 构造请求参数
-  const params = {
-    chat_session_id: session_id.value, // 替换为实际的会话 ID
-    prompt: inputText.value,
-    ref_file_ids: [],
-    thinking_enabled: isThinking.value,
-  };
-  inputText.value = ''; // 清空输入框
-  try {
-    // 发送 POST 请求
-    const response = await fetch('http://182.92.126.35:6005/chat_stream', {
-      method: 'POST',
-      headers: {
-        'Content-Type': 'application/json',
-      },
-      body: JSON.stringify(params),
-    });
-
-    // 检查响应是否成功
-    if (!response.ok) {
-      throw new Error('Network response was not ok');
-    }
-
-    // 获取可读流
-    const reader = response.body.getReader();
-
-    // 创建一条新的消息对象
-    const newMessage = {
-      id: `response_${Date.now()}`,
-      type: 'response', // 消息类型
-      content: '',
-      content1: '',
-      Origintype: '',
-      timestamp: Date.now(), // 时间戳用来排序
-    };
-
-    // 将新消息添加到消息列表
-    messageList.value.push(newMessage);
-
-    // 读取流式数据
-    while (true) {
-      const { done, value } = await reader.read();
-      if (done) {
-        console.log('Stream complete');
-        break;
-      }
-
-      // 将流数据转换为字符串
-      const chunk = new TextDecoder().decode(value);
-      console.log('Received chunk:', chunk);
-
-      // 使用正则表达式匹配完整的 JSON 对象
-      const jsonRegex = /{.*?}/g;
-      const matches = chunk.match(jsonRegex);
-      if (matches) {
-        matches.forEach((match) => {
-          try {
-            const data = JSON.parse(match);
-            console.log(data.type, '数据类型11111111111111111');
-            if (data.type === 'thinking') {
-              // 找到当前消息对象并更新 content
-              const targetMessage = messageList.value.find((msg) => msg.id === newMessage.id);
-              if (targetMessage) {
-                targetMessage.content += data.content; // 追加内容
-                targetMessage.Origintype = data.type;
-                scrollToBottom();
-              }
-            }
-            if (data.type === 'text') {
-              // 找到当前消息对象并更新 content
-              const targetMessage = messageList.value.find((msg) => msg.id === newMessage.id);
-              if (targetMessage) {
-                targetMessage.content1 += data.content; // 追加内容
-                targetMessage.Origintype1 = data.type;
-                scrollToBottom();
-              }
-            }
-          } catch (error) {
-            console.error('Failed to parse JSON:', error);
-          }
-        });
-      }
-    }
-  } catch (error) {
-    // 请求失败时设置系统消息
-    if (!response || !response.ok) {
-      systemMessage.value = '服务器异常';
-      messageList.value.push({
-        id: `system_${Date.now()}`,
-        type: 'system',
-        content: systemMessage.value,
-        Origintype: 'text',
-        timestamp: Date.now(),
-      });
-      console.error('请求失败:', error);
-    }
-  } finally {
-    spinning.value = false; // 停止加载
-  }
 };
-//创建标题
-async function createSessionTitle({ session_id, title }) {
-  const params = {
-    chat_session_id: session_id,
-    prompt: title,
-  };
-  let response = await fetch('http://182.92.126.35:6005/sessions/title', {
-    method: 'post',
-    headers: {
-      'Content-Type': 'application/json',
-    },
-    body: JSON.stringify(params),
-  });
-  const data = await response.json();
-}
-//获取会话历史
-async function sessionsHistoryList() {
-  const params = {
-    user_id: userId,
-  };
-  let response = await fetch(`http://182.92.126.35:6005/sessions`, {
-    method: 'post',
-    headers: {
-      'Content-Type': 'application/json',
-    },
-    body: JSON.stringify(params),
-  });
-  const data = await response.json();
-  historySessions.value = data.chat_sessions;
-}
-//获取具体会话记录
-async function sessionsHistory(id: string) {
-  let response = await fetch(`http://182.92.126.35:6005/sessions/history_chat/?chat_session_id=${id}`, {
-    method: 'get',
-    headers: {
-      'Content-Type': 'application/json',
-    },
-  });
-  const data = await response.json();
-  if (data.chat_messages.length > 0) {
-    messageList.value = [];
-    data.chat_messages.forEach((item: any) => {
-      // role== user 用户提问
-      if (item.role === 'user') {
-        messageList.value.push({
-          id: `user_${Date.now()}`,
-          type: 'user',
-          content: item.content,
-          timestamp: Date.now(),
-        });
-      } else if (item.role === 'assistant') {
-        // role== assistant 机器回答
-        if (item.thinking_enabled) {
-          messageList.value.push({
-            id: `system_${Date.now()}_thinking`,
-            type: 'system',
-            content: item.thinking_content,
-            Origintype: 'thinking',
-            timestamp: Date.now(),
-          });
-          messageList.value.push({
-            id: `system_${Date.now()}_text`,
-            type: 'system',
-            content1: item.content,
-            Origintype1: 'text',
-            timestamp: Date.now(),
-          });
-        } else {
-          messageList.value.push({
-            id: `system_${Date.now()}`,
-            type: 'system',
-            content: item.content,
-            timestamp: Date.now(),
-          });
-        }
-
-        console.log(item.content);
-      }
-    });
-  }
-}
-//格式化消息
-function formatMessage(text: string) {
-  let formatted = text
-    // 处理换行
-    .replace(/\n\n/g, '<br>')
-    .replace(/\n###/g, '<br> ')
-    .replace(/###/g, '')
-    .replace(/---/g, '')
-    // 处理粗体
-    .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
-    // 处理斜体
-    .replace(/\*(.*?)\*/g, '<em>$1</em>')
-    // 处理行内代码
-    .replace(/`([^`]+)`/g, '<code>$1</code>');
-  return formatted;
-}
-// 初始化按钮定位
-onMounted(() => {
-  sessionsHistoryList();
-});
 </script>
 
 <style lang="less" scoped>
-@keyframes menuShow {
-  0% {
-    width: 0;
-    height: 0;
-  }
-  100% {
-    width: 480px;
-    height: 100vh;
-  }
-}
-.custom-list {
-  height: 360px;
-  overflow-y: auto;
-}
-/* 穿透组件作用域 */
-::v-deep .custom-list {
-  scrollbar-width: thin;
-  scrollbar-color: #1890ff #f0f0f0;
-  &::-webkit-scrollbar {
-    width: 4px;
-    height: 6px;
-  }
-
-  &::-webkit-scrollbar-thumb {
-    background: #1890ff;
-    border-radius: 4px;
-  }
-
-  &::-webkit-scrollbar-track {
-    background: #f0f0f0;
-    border-radius: 4px;
-  }
-}
-::v-deep .zxm-list-items {
-  color: #1890ff;
-}
-::v-deep .zxm-list-item:hover {
-  text-decoration: underline;
-  color: #1890ff !important;
-}
-.text-container {
-  display: flex;
-  align-items: center;
-  width: 100%;
-  overflow: hidden;
-}
-
-.text-ellipsis {
-  flex: 1;
-}
-.edit-text {
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-  min-width: 0;
-}
-.edit-icon {
-  flex-shrink: 0;
-  cursor: pointer;
-  margin-left: auto;
-}
-.edit-input {
-  font-size: 10px;
-}
 .trigger-button {
   position: fixed;
   bottom: 10px;
@@ -595,300 +29,7 @@ onMounted(() => {
     background-image: url('/@/assets/images/vent/home/wakeBtn.png');
     background-position: center;
     background-size: 100% 100%;
+    cursor: pointer;
   }
 }
-.dialog-overlay {
-  width: 32%;
-  height: 55%;
-  z-index: 999;
-  display: flex;
-  position: fixed;
-  right: 90px;
-  bottom: 20px;
-  box-shadow: 0 0 3px 3px #1074c1;
-  background-color: #09172c;
-}
-
-/* 遮罩层淡入淡出 */
-.fade-enter-active,
-.fade-leave-active {
-  transition: opacity 0.3s;
-}
-.fade-enter-from,
-.fade-leave-to {
-  opacity: 0;
-}
-
-/* 弹窗缩放动画 */
-.scale-enter-active,
-.scale-leave-active {
-  transition: all 0.3s ease;
-}
-.scale-enter-from {
-  transform: scale(0.5) translate(-50%, -50%);
-  opacity: 0;
-}
-.scale-leave-to {
-  transform: scale(1.2) translate(-50%, -50%);
-  opacity: 0;
-}
-
-.left-side {
-  background: #0c2842;
-  transition: width 0.5s ease; /* 平滑过渡动画 */
-  width: 120px; /* 展开时宽度 */
-  position: relative; /* 用于按钮定位 */
-}
-.left-side.collapsed {
-  width: 40px; /* 折叠时宽度 */
-}
-
-.addBtn {
-  height: 30px;
-  position: absolute;
-  background-size: 100% 100%;
-  background-position: center;
-  padding: 2px;
-  right: 10px;
-  top: 10px;
-  left: 10px;
-  align-items: center;
-  border-radius: 3px;
-  cursor: pointer;
-}
-.btn-text-bg {
-  width: 14px;
-  height: 14px;
-  position: absolute;
-  background-size: 100% 100%;
-  right: 10px;
-  top: 9px;
-  left: 10px;
-  bottom: 10px;
-}
-.btn-text {
-  margin-left: 3px;
-  font-size: 12px;
-  color: #fff;
-  white-space: nowrap;
-  margin-left: 30px;
-  line-height: 26px;
-}
-.historyBtn {
-  width: 20px;
-  height: 20px;
-  position: absolute;
-  background-size: 100% 100%;
-  background-position: center;
-  padding: 2px;
-  right: 10px;
-  top: 100px;
-}
-.historyBtn1 {
-  width: 20px;
-  height: 20px;
-  position: absolute;
-  background-size: 100% 100%;
-  background-position: center;
-  left: 3px;
-  top: 80px;
-}
-.divider0 {
-  border-bottom: 1px solid #1074c1;
-  width: auto;
-  margin: 0 10px;
-  height: 13%;
-  display: block;
-  background: transparent;
-}
-.foldBtn {
-  width: 20px;
-  height: 20px;
-  position: absolute;
-  background-size: 100% 100%;
-  background-position: center;
-  padding: 2px;
-  right: 10px;
-  bottom: 10px;
-  cursor: pointer;
-}
-
-.right-side {
-  flex: 1; /* 占据剩余空间 */
-  background: #09172c;
-}
-
-.input-content {
-  display: flex;
-  flex-direction: column;
-  justify-content: flex-end; /* 内容底部对齐 */
-  height: 100%;
-  padding: 20px; /* 统一内边距 */
-}
-.ask-message {
-  align-self: flex-end;
-  float: right;
-  max-width: 70%;
-  padding: 10px;
-  margin: 10px;
-  border-radius: 5px;
-  color: #fff;
-  background: #0c2842;
-  align-self: flex-end; /* 右侧对齐‌:ml-citation{ref="2" data="citationList"} */
-}
-.answer {
-  display: flex;
-  flex-direction: row;
-}
-.answerIcon {
-  flex-shrink: 0;
-  margin-top: 10px;
-  width: 35px;
-  height: 35px;
-  background-image: url('/@/assets/images/vent/home/answerIcon.svg');
-  background-size: 100% 100%;
-}
-.answer-message {
-  float: left;
-  padding: 10px;
-  margin: 10px;
-  border-radius: 5px;
-  background: #0c2842;
-}
-.thinking-text {
-  color: gray;
-  font-size: 12px;
-}
-.answer-text {
-  color: #fff;
-}
-/** 系统返回信息**/
-.system-message {
-  display: flex;
-  flex-direction: row;
-  align-self: flex-start;
-  width: 100%;
-  padding: 12px;
-  display: flex;
-}
-.answerIcon {
-  margin-top: 10px;
-  width: 35px;
-  height: 35px;
-  background-image: url('/@/assets/images/vent/home/answerIcon.svg');
-  background-size: 100% 100%;
-}
-.think-area {
-  color: #7979799f;
-}
-.answer-area {
-  color: #fff;
-}
-.dialog-area {
-  flex: 1; /* 占据剩余空间 */
-  gap: 50px; /* 消息块间隔统一控制 */
-  overflow-y: auto; /* 垂直滚动条 */
-  margin-bottom: 10px;
-}
-.loading-wrapper,
-.content-wrapper {
-  min-height: 40px;
-}
-.message-item.user {
-  margin-bottom: 50px;
-}
-.input-area {
-  background-color: #043256 !important;
-  display: flex;
-  flex-direction: column;
-  gap: 10px;
-}
-textarea {
-  background-color: #043256 !important;
-  width: 100%;
-  height: 40px;
-  border: none;
-  resize: none;
-  outline: none;
-  overflow: hidden;
-  padding: 10px; /* 统一内边距 */
-  color: #fff;
-}
-
-.action-bar {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 8px 16px;
-}
-
-.think-btn {
-  border: 1px solid #ccc;
-  width: 120px;
-  height: 20px;
-  line-height: 20px;
-  text-align: center;
-  border-radius: 50px;
-  cursor: pointer;
-  background: white;
-  transition: background 0.3s;
-}
-
-.think-btn.active {
-  background: #1890ff;
-  color: white;
-  border-color: #1890ff;
-}
-.right-actions {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-}
-
-.upload-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-}
-.upload-btn {
-  float: right;
-  display: flex;
-  cursor: pointer;
-  padding: 6px 12px;
-}
-
-.divider {
-  color: #ccc;
-  font-weight: 300;
-  margin: 0 10px;
-}
-
-.send-file {
-  width: 20px;
-  height: 20px;
-  background-image: url('/@/assets/images/vent/home/sendFile.svg');
-  background-size: 100% 100%;
-  border-radius: 4px;
-  cursor: pointer;
-}
-.send-img {
-  width: 20px;
-  height: 20px;
-  background-image: url('/@/assets/images/vent/home/sendImg.svg');
-  background-size: 100% 100%;
-  border-radius: 4px;
-  cursor: pointer;
-}
-.send-btn {
-  width: 20px;
-  height: 20px;
-  margin-left: 10px;
-  margin-right: 10px;
-  background-color: #1074c1;
-  background-image: url('/@/assets/images/vent/home/send.svg');
-  background-position: center;
-  background-size: 100% 100%;
-  border-radius: 2px;
-  cursor: pointer;
-}
 </style>