feat: 历史消息的加载

This commit is contained in:
zoujing
2026-02-03 16:34:16 +08:00
parent aff9233ce2
commit ff5355855f
5 changed files with 158 additions and 114 deletions

View File

@@ -1,14 +1,64 @@
/* eslint-disable */
// @ts-ignore
import { getRequest, ResponseModel } from '@utils/request'
import { getRequest, postRequest, ResponseModel } from '@utils/request'
/** 创建会话 创建会话创建会话 GET /agent/assistant/createConversation */
export interface CreateConversationResponse {
conversationId: string
}
/** 创建会话 创建会话创建会话 GET /agent/assistant/createConversation */
export const createConversation = async () => {
const res: ResponseModel = await getRequest('/agent/assistant/createConversation')
return res.data as CreateConversationResponse
}
/** 获取会话列表 获取会话列表获取会话列表 POST /agent/assistant/conversationList */
export interface ConversationListRequest {
pageSize: number
pageNum: number
conversationId?: string
}
export interface ConversationListResponse {
records: Array<ConversationListRecords>
total: number
size: number
current: number
optimizeCountSql: boolean
searchCount: boolean
}
export interface ConversationListRecords {
conversationTitle: string
conversationId: string
}
export interface ConversationMessageListResponse {
records: Array<ConversationMessageListRecords>
total: number
size: number
current: number
optimizeCountSql: boolean
searchCount: boolean
}
export interface ConversationMessageListRecords {
messageId: string
conversationId: string
messageType: string
messageContent: string
messageDisplay: string
messageSenderId: string
messageSenderRole: string
messageTime: string
}
export const getConversationList = async (params: ConversationListRequest) => {
const res: ResponseModel = await postRequest('/agent/assistant/conversationList', params)
return res.data as ConversationListResponse
}
export const conversationMessageList = async (params: ConversationListRequest) => {
const res: ResponseModel = await postRequest('/agent/assistant/conversationMessageList', params)
return res.data as ConversationMessageListResponse
}

View File

@@ -87,7 +87,7 @@ instance.interceptors.request.use(
// 添加响应拦截器
instance.interceptors.response.use(
(res) => {
console.log("🚀 ~ response:", res.data)
console.log(`🚀 ~ response: \n url:${res.config.url} \n params:${JSON.stringify(res.config.params)} \n data:\n ${JSON.stringify(res.data)}`)
// 未设置状态码则默认成功状态
const code = res.data.code || 200
// 获取错误信息

View File

@@ -88,12 +88,13 @@ import { Session } from '../../utils/storage';
import userAvatar from '@assets/images/login/user_icon.png';
import aiAvatar from '@assets/images/login/blue_logo.png';
import { createConversation } from '../../api/ConversationApi';
import { createConversation, conversationMessageList } from '../../api/ConversationApi';
import { ElMessage, ElLoading } from 'element-plus'
// 支持外部通过 prop 控制是否为引导页
const props = defineProps({
guide: { type: Boolean, default: true }
guide: { type: Boolean, default: true },
conversationId: { type: String, default: '' }
});
const emit = defineEmits(['update:guide']);
@@ -127,7 +128,16 @@ const isSendingMessage = ref(false);
/// agentId 首页接口中获取 1953462165250859010
const agentId = ref("1953462165250859010");
/// 会话ID 历史数据接口中获取
const conversationId = ref("");
const conversationId = ref(props.conversationId);
// 监听 conversationId prop 变化,只有当有值时(选择历史消息)才请求消息列表
watch(() => props.conversationId, (newId) => {
if (newId) {
conversationId.value = newId;
loadConversationMessages(newId);
}
});
// 会话进行中标志
const isSessionActive = ref(false);
/// 指令通用消息类型
@@ -285,9 +295,35 @@ const checkToken = async () => {
};
// 调用接口创建新会话
const createConversationRequest = async () => {
const createConversationRequest = async (): Promise<string | null> => {
const res = await createConversation();
conversationId.value = res.conversationId;
if (res && res.conversationId) {
conversationId.value = res.conversationId;
console.log("创建新会话ID:", conversationId.value);
return res.conversationId;
} else {
console.log("创建会话失败,接口返回异常");
return null;
}
};
// 加载历史会话消息
const loadConversationMessages = async (convId: string) => {
try {
const res = await conversationMessageList({ conversationId: convId, pageSize: 50, pageNum: 1 });
// 将消息转换为 ChatMessage 格式
chatMsgList.value = res.records.map((msg: any) => ({
messageId: msg.messageId,
messageRole: msg.messageSenderRole === 'user' ? MessageRole.ME : MessageRole.AI,
messageContent: msg.messageContent,
finished: true, // 历史消息已完成
}));
console.log("加载历史消息:", chatMsgList.value);
// 加载历史消息后滚动到底部
nextTick(() => scrollToBottom());
} catch (error) {
console.error("加载历史消息失败:", error);
}
};
/// =============对话↓================

View File

@@ -5,130 +5,79 @@
<div class="font-bold text-gray-80">YINIAN</div>
</div>
<div class="flex justify-center m-2 bg-white rounded-lg p-2.5 border-[##E5E8EE] shadow-sm text-center" @click="addNewChat">
<div class="flex justify-center m-2 bg-white rounded-lg p-2.5 border-[##E5E8EE] shadow-sm text-center"
@click="addNewChat">
<RiAddLine /> 新对话
</div>
<div class="overflow-y-auto p-2 ">
<section v-for="(group, index) in groups" :key="group.title" class="mb-3">
<div class="flex items-center justify-between text-sm text-gray-500" @click="selectGroupKey(index)">
<span>{{ group.title }}</span>
<RiArrowDownSLine v-show="group.selected" color="rgba(153,160,174,1)" />
<RiArrowRightSLine v-show="!group.selected" color="rgba(153,160,174,1)" />
</div>
<ul class="list-none mt-1.5" v-if="group.selected">
<li v-for="item in group.items" :key="item.id" @click="selectedHistoryMessage(item.id)" :class="[
<ul class="list-none">
<li v-for="item in groups" :key="item.conversationId" @click="selectedHistoryMessage(item.conversationId)"
:class="[
'flex items-center gap-2 p-2 text-gray-600 rounded-lg cursor-pointer transition-colors',
item.id === selectedId ? 'bg-white shadow-sm border-[##E5E8EE]' : 'hover:bg-gray-50'
item.conversationId === selectedConversationId ? 'bg-white shadow-sm border-[##E5E8EE]' : 'hover:bg-gray-50'
]">
<span class="w-2 h-2 rounded-full bg-[#BEDBFF] flex-none"></span>
<div class="flex-1 min-w-0">
<div class="truncate text-sm">{{ item.title }}</div>
</div>
<button v-if="item.id === selectedId"
class="bg-transparent border-0 text-gray-500 text-lg px-1 py-0"></button>
</li>
</ul>
</section>
<span class="w-2 h-2 rounded-full bg-[#BEDBFF] flex-none"></span>
<div class="flex-1 min-w-0">
<div class="truncate text-sm">{{ item.conversationId }}</div>
</div>
<button v-if="item.conversationId === selectedConversationId"
class="bg-transparent border-0 text-gray-500 text-lg px-1 py-0"></button>
</li>
</ul>
</div>
</aside>
</template>
<script setup lang="ts">
import { ref, defineEmits } from 'vue'
import { ref, onMounted, defineEmits } from 'vue'
import { RiAddLine, RiArrowRightSLine, RiArrowDownSLine } from '@remixicon/vue'
import { getConversationList } from '../../api/ConversationApi';
interface HistoryMessage {
conversationId: string;
conversationTitle: string;
}
/// 记录选择的历史消息ID
const selectedId = ref<number | null>(2)
const selectedConversationId = ref<string>('')
/// 历史消息分组数据
const groups = ref([
{
title: '近3天',
selected: false,
items: [
{ id: 1, title: '这是一段对话' },
{ id: 2, title: '这是一段对话' },
{ id: 3, title: '这是一段对话这是一段对话这是一段对话' },
{ id: 4, title: '这是一段对话这是一段对话' },
{ id: 5, title: '这是一段对话这是一段对话' }
]
},
{
title: '近7天',
selected: false,
items: [
{ id: 6, title: '这是一段对话' },
{ id: 7, title: '这是一段对话' },
{ id: 8, title: '这是一段对话这是一段对话' },
{ id: 9, title: '这是一段对话这是一段对话' }
]
},
{
title: '近15天',
selected: false,
items: [
{ id: 10, title: '这是一段对话' },
{ id: 11, title: '这是一段对话' },
{ id: 12, title: '这是一段对话这是一段对话这是一段对话' },
{ id: 13, title: '这是一段对话这是一段对话' },
{ id: 14, title: '这是一段对话这是一段对话' }
]
},
{
title: '近30天',
selected: false,
items: [
{ id: 15, title: '这是一段对话' },
{ id: 16, title: '这是一段对话' },
{ id: 17, title: '这是一段对话这是一段对话' },
{ id: 18, title: '这是一段对话这是一段对话' }
]
},
{
title: '近60天',
selected: false,
items: [
{ id: 19, title: '这是一段对话' },
{ id: 20, title: '这是一段对话' },
{ id: 21, title: '这是一段对话这是一段对话这是一段对话' },
{ id: 22, title: '这是一段对话这是一段对话' },
{ id: 23, title: '这是一段对话这是一段对话' }
]
},
{
title: '近90天',
selected: false,
items: [
{ id: 24, title: '这是一段对话' },
{ id: 25, title: '这是一段对话' },
{ id: 26, title: '这是一段对话这是一段对话' },
{ id: 27, title: '这是一段对话这是一段对话' }
]
}
])
const groups = ref<Array<HistoryMessage>>([])
/// 选择历史消息
const selectedHistoryMessage = (id: number) => {
selectedId.value = id
}
/// 选择分组展开/收起
const selectGroupKey = (index: number) => {
groups.value.forEach((group, i) => {
if (i === index) {
group.selected = !group.selected
}
})
}
/// TODO: 添加新对话
const emit = defineEmits(['new-chat'])
/// 定义事件
const emit = defineEmits(['new-chat', 'select-chat'])
/// 添加新对话
const addNewChat = () => {
console.log('add new chat')
// 触发新对话事件
emit('new-chat')
// 清空选择的历史消息ID
selectedConversationId.value = ''
// 获取最新的历史会话列表
getHistoryConversationList()
}
/// 选择历史消息
const selectedHistoryMessage = (conversationId: string) => {
selectedConversationId.value = conversationId
emit('select-chat', conversationId)
}
/// 页面加载时获取历史会话列表
onMounted(() => {
getHistoryConversationList()
})
/// 获取历史会话列表
const getHistoryConversationList = async () => {
const list = await getConversationList({ pageSize: 20, pageNum: 1 })
if (!list || !list.records) return;
groups.value.push(...list.records.map((item: any) => ({
conversationId: item.conversationId,
conversationTitle: item.conversationTitle
})))
}
</script>

View File

@@ -1,9 +1,9 @@
<template>
<layout>
<div class="flex h-full w-full flex-col md:flex-row ">
<ChatHistory class="flex-none w-50" @new-chat="guide = true" />
<ChatHistory class="flex-none w-50" @new-chat="guide = true" @select-chat="handleSelectChat" />
<div class="flex-1 mr-2 overflow-hidden bg-white rounded-xl">
<ChatBox v-model:guide="guide" />
<ChatBox v-model:guide="guide" :conversationId="selectedConversationId" />
</div>
<TaskList />
</div>
@@ -15,6 +15,15 @@ import TaskList from '@renderer/components/TaskList/index.vue'
import ChatHistory from './ChatHistory.vue'
import ChatBox from './ChatBox.vue'
import { ref } from 'vue'
/// 是否显示引导页
const guide = ref(true)
/// 选择的历史会话ID
const selectedConversationId = ref('')
/// 选择历史会话
const handleSelectChat = (conversationId: string) => {
guide.value = false;
selectedConversationId.value = conversationId;
};
</script>