|
@@ -1,849 +1,38 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
<div class="trigger-button">
|
|
|
- <div class="icon" @click="openMenu"></div>
|
|
|
+ <div class="icon" @click="openMenu" :style="{ zIndex: 1000 }"></div>
|
|
|
+ <Aichat
|
|
|
+ style="width: 32%; height: 55%; z-index: 999; position: fixed; right: 90px; bottom: 20px; box-shadow: 0 0 3px 3px #1074c1"
|
|
|
+ :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-html="formatMessage(message.content)"></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;
|
|
|
-}
|
|
|
-let userId = unref(userStore.getUserInfo).id;
|
|
|
-// const userId = ref(0);
|
|
|
-type MessageItem = {
|
|
|
- id: string; // 唯一标识(可用时间戳生成)
|
|
|
- type: 'user' | 'system';
|
|
|
- content: 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,
|
|
|
+ import { ref } from 'vue';
|
|
|
+ import Aichat from '/@/components/AIChat/index.vue';
|
|
|
+ const dialogVisible = ref(false);
|
|
|
+ const openMenu = () => {
|
|
|
+ dialogVisible.value = !dialogVisible.value;
|
|
|
};
|
|
|
- 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: '',
|
|
|
- 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);
|
|
|
- if (data.type === 'text') {
|
|
|
- // 找到当前消息对象并更新 content
|
|
|
- const targetMessage = messageList.value.find((msg) => msg.id === newMessage.id);
|
|
|
- if (targetMessage) {
|
|
|
- targetMessage.content += data.content; // 追加内容
|
|
|
- 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,
|
|
|
- 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 {
|
|
|
- // role== assistant 机器回答
|
|
|
- messageList.value.push({
|
|
|
- id: `system_${Date.now()}`,
|
|
|
- type: 'system',
|
|
|
- content: item.content,
|
|
|
- timestamp: Date.now(),
|
|
|
- });
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-}
|
|
|
-//格式化消息
|
|
|
-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;
|
|
|
- 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%;
|
|
|
+ .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%;
|
|
|
+ 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;
|
|
|
-}
|
|
|
-
|
|
|
-/** 系统返回信息**/
|
|
|
-.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>
|