Kaynağa Gözat

备份Aichat组件

bobo04052021@163.com 2 hafta önce
ebeveyn
işleme
2b4c8e7c9c
1 değiştirilmiş dosya ile 905 ekleme ve 0 silme
  1. 905 0
      src/layouts/default/sider/Aichat copy.vue

+ 905 - 0
src/layouts/default/sider/Aichat copy.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>