|
@@ -39,27 +39,13 @@
|
|
|
}"
|
|
|
></span>
|
|
|
<span v-if="!isFold" class="btn-text">历史对话</span>
|
|
|
- <!-- <a-list style="width: 90px" :split="false" :data-source="historySessions" class="custom-list">
|
|
|
- <template #renderItem="{ item }">
|
|
|
- <a-list-item
|
|
|
- :style="{
|
|
|
- padding: '8px 10px 0 8px',
|
|
|
- color: '#5e7081',
|
|
|
- fontSize: '12px',
|
|
|
- }"
|
|
|
- @click="sessionsHistory(item.id)"
|
|
|
- >
|
|
|
- {{ item.title ? item.title : '新会话' }}
|
|
|
- </a-list-item>
|
|
|
- </template>
|
|
|
- </a-list> -->
|
|
|
<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: '12px',
|
|
|
+ fontSize: '10px',
|
|
|
position: 'relative', // 新增定位
|
|
|
}"
|
|
|
@click="sessionsHistory(item.id)"
|
|
@@ -67,12 +53,20 @@
|
|
|
<!-- 新增flex布局容器 -->
|
|
|
<div style="display: flex; justify-content: space-between; width: 100%">
|
|
|
<div v-if="editingId !== item.id" class="text-container">
|
|
|
- {{ item.title || '新会话' }}
|
|
|
+ <span class="edit-text">{{ item.title || '新会话' }}</span>
|
|
|
<edit-outlined class="edit-icon" @click="startEditing(item)" />
|
|
|
</div>
|
|
|
|
|
|
<!-- 输入框 -->
|
|
|
- <a-input v-else v-model:value="editText" v-focus @blur="handleSave(item)" @keyup.enter="handleSave(item)" class="edit-input" />
|
|
|
+ <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>
|
|
@@ -103,7 +97,6 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <!-- </div> -->
|
|
|
</div>
|
|
|
<!-- 文本输入区域 -->
|
|
|
<div v-if="spinning" class="thinking-area">
|
|
@@ -167,6 +160,13 @@ const sortedMessages = computed(() => {
|
|
|
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) {
|
|
@@ -290,37 +290,85 @@ async function sendMessage() {
|
|
|
}
|
|
|
}
|
|
|
//发送消息 流式响应
|
|
|
-async function sendMessage1() {
|
|
|
- spinning.value = true;
|
|
|
- // 添加用户消息
|
|
|
+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,
|
|
|
+ chat_session_id: session_id.value, // 替换为实际的会话 ID
|
|
|
prompt: inputText.value,
|
|
|
ref_file_ids: [],
|
|
|
thinking_enabled: false,
|
|
|
};
|
|
|
inputText.value = ''; // 清空输入框
|
|
|
- //将用户输入的内容发送到后端
|
|
|
try {
|
|
|
- // 将用户输入的内容发送到后端;
|
|
|
- let response = await fetch('http://182.92.126.35:6005/chat_stream', {
|
|
|
+ // 发送 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);
|
|
|
+ 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) {
|
|
|
- // 请求失败时设置系统消息为"服务器异常"
|
|
|
+ // 请求失败时设置系统消息
|
|
|
systemMessage.value = '服务器异常';
|
|
|
messageList.value.push({
|
|
|
id: `system_${Date.now()}`,
|
|
@@ -330,9 +378,9 @@ async function sendMessage1() {
|
|
|
});
|
|
|
console.error('请求失败:', error);
|
|
|
} finally {
|
|
|
- spinning.value = false; // 无论请求成功与否,都停止加载指示器
|
|
|
+ spinning.value = false; // 停止加载
|
|
|
}
|
|
|
-}
|
|
|
+};
|
|
|
//创建标题
|
|
|
async function createSessionTitle({ session_id, title }) {
|
|
|
const params = {
|
|
@@ -451,9 +499,6 @@ onMounted(() => {
|
|
|
border-radius: 4px;
|
|
|
}
|
|
|
}
|
|
|
-::v-deep .zxm-list-item {
|
|
|
- white-space: normal; /* 禁止文本换行 */
|
|
|
-}
|
|
|
::v-deep .zxm-list-items {
|
|
|
color: #1890ff;
|
|
|
}
|
|
@@ -461,6 +506,30 @@ onMounted(() => {
|
|
|
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;
|
|
@@ -668,7 +737,7 @@ onMounted(() => {
|
|
|
}
|
|
|
.loading-wrapper,
|
|
|
.content-wrapper {
|
|
|
- min-height: 40px; /* 避免高度塌陷 */
|
|
|
+ min-height: 40px;
|
|
|
}
|
|
|
.message-item.user {
|
|
|
margin-bottom: 50px;
|