Files
Yi.Framework/Yi.Ai.Vue3/src/stores/modules/session.ts
2026-01-01 18:53:27 +08:00

250 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { ChatSessionVo, CreateSessionDTO, GetSessionListParams } from '@/api/session/types';
import { ChatLineRound } from '@element-plus/icons-vue';
import { defineStore } from 'pinia';
import { markRaw } from 'vue';
import { useRouter } from 'vue-router';
import {
create_session,
delete_session,
get_session,
get_session_list,
update_session,
} from '@/api';
import { useUserStore } from './user';
export const useSessionStore = defineStore('session', () => {
const router = useRouter();
const userStore = useUserStore();
// 当前选中的会话信息
const currentSession = ref<ChatSessionVo | null>(null);
// 设置当前会话
const setCurrentSession = (session: ChatSessionVo | null) => {
currentSession.value = session;
};
// 会话列表核心状态
const sessionList = ref<ChatSessionVo[]>([]); // 会话数据列表
const currentPage = ref(1); // 当前页码从1开始
const pageSize = ref(25); // 每页显示数量
const hasMore = ref(true); // 是否还有更多数据
const isLoading = ref(false); // 全局加载状态(初始加载/刷新)
const isLoadingMore = ref(false); // 加载更多状态(区分初始加载)
// 创建新对话(按钮点击)
const createSessionBtn = async () => {
try {
// 清空当前选中会话信息
setCurrentSession(null);
await router.replace({ name: 'chatConversation' });
}
catch (error) {
console.error('createSessionBtn错误:', error);
}
};
// 获取会话列表(核心分页方法)
const requestSessionList = async (page: number = currentPage.value, force: boolean = false) => {
// 如果没有token就直接清空
if (!userStore.token) {
sessionList.value = [];
return;
}
if (!force && ((page > 1 && !hasMore.value) || isLoading.value || isLoadingMore.value))
return;
isLoading.value = page === 1; // 第一页时标记为全局加载
isLoadingMore.value = page > 1; // 非第一页时标记为加载更多
try {
const params: GetSessionListParams = {
userId: userStore.userInfo?.userId as number,
skipCount: page,
maxResultCount: pageSize.value,
isAsc: 'desc',
orderByColumn: 'createTime',
};
const resArr = await get_session_list(params);
// 预处理会话分组 并添加前缀图标
const res = processSessions(resArr.data.items);
const allSessions = new Map(sessionList.value.map(item => [item.id, item])); // 现有所有数据
res.forEach(item => allSessions.set(item.id, { ...item })); // 更新/添加数据
// 按服务端排序重建列表(假设分页数据是按时间倒序,第一页是最新,后续页依次递减)
// 此处需根据接口返回的排序规则调整,假设每页数据是递增的(第一页最新,第二页次新,第三页 oldest
if (page === 1) {
// 第一页是最新数据,应排在列表前面
sessionList.value = [
...res, // 新的第一页数据(最新)
...Array.from(allSessions.values()).filter(item => !res.some(r => r.id === item.id)), // 保留未被第一页覆盖的旧数据
];
}
else {
// 非第一页数据是更旧的数据,追加到列表末尾
sessionList.value = [
...sessionList.value.filter(item => !res.some(r => r.id === item.id)), // 保留现有数据(除了被当前页更新的)
...res, // 追加当前页的新数据(更旧的)
];
}
// 判断是否还有更多数据(当前页数据量 < pageSize 则无更多)
if (!force)
hasMore.value = (res?.length || 0) === pageSize.value;
if (!force)
currentPage.value = page; // 仅非强制刷新时更新页码
}
catch (error) {
console.error('requestSessionList错误:', error);
}
finally {
isLoading.value = false;
isLoadingMore.value = false;
}
};
// 发送消息后创建新会话
const createSessionList = async (data: Omit<CreateSessionDTO, 'id'>) => {
if (!userStore.token) {
router.replace({
name: 'chatConversationWithId',
params: {
id: 'not_login',
},
});
return;
}
try {
const res = await create_session(data);
// TODO: 模拟请求
// const res = {
// code: 200,
// msg: "操作成功",
// data: "1935711019560206338"
// };
// 创建会话后立刻查询列表会话
// 1. 先找到被修改会话在 sessionList 中的索引(假设 sessionList 是按服务端排序的完整列表)
const targetIndex = sessionList.value.findIndex(session => session.id === `${res.data}`);
// 2. 计算该会话所在的页码(页大小固定为 pageSize.value
const targetPage
= targetIndex >= 0
? Math.floor(targetIndex / pageSize.value) + 1 // 索引从0开始页码从1开始
: 1; // 未找到时默认刷新第一页(可能因排序变化导致位置改变)
// 3. 刷新目标页数据
await requestSessionList(targetPage, true);
// 并将当前勾选信息设置为新增的会话信息
const newSessionRes = await get_session(`${res.data.id}`);
setCurrentSession(newSessionRes.data);
// 跳转聊天页
router.replace({
name: 'chatConversationWithId',
params: { id: `${res.data.id}` },
});
}
catch (error) {
console.error('createSessionList错误:', error);
}
};
// 加载更多会话(供组件调用)
const loadMoreSessions = async () => {
if (hasMore.value)
await requestSessionList(currentPage.value + 1);
};
// 更新会话(供组件调用)
const updateSession = async (item: ChatSessionVo) => {
try {
await update_session(item);
// 1. 先找到被修改会话在 sessionList 中的索引(假设 sessionList 是按服务端排序的完整列表)
const targetIndex = sessionList.value.findIndex(session => session.id === item.id);
// 2. 计算该会话所在的页码(页大小固定为 pageSize.value
const targetPage
= targetIndex >= 0
? Math.floor(targetIndex / pageSize.value) + 1 // 索引从0开始页码从1开始
: 1; // 未找到时默认刷新第一页(可能因排序变化导致位置改变)
// 3. 刷新目标页数据
await requestSessionList(targetPage, true);
}
catch (error) {
console.error('updateSession错误:', error);
}
};
// 删除会话(供组件调用)
const deleteSessions = async (ids: string[]) => {
try {
// todo cc这里删除返回空的body结果炸了报错堆栈都没有
await delete_session(ids);
// 1. 先找到被修改会话在 sessionList 中的索引(假设 sessionList 是按服务端排序的完整列表)
const targetIndex = sessionList.value.findIndex(session => session.id === ids[0]);
// 2. 计算该会话所在的页码(页大小固定为 pageSize.value
const targetPage
= targetIndex >= 0
? Math.floor(targetIndex / pageSize.value) + 1 // 索引从0开始页码从1开始
: 1; // 未找到时默认刷新第一页(可能因排序变化导致位置改变)
// 3. 刷新目标页数据
await requestSessionList(targetPage, true);
}
catch (error) {
console.error('deleteSessions错误:', error);
}
};
// 在获取会话列表后添加预处理逻辑(示例)
function processSessions(sessions: ChatSessionVo[]) {
const currentDate = new Date();
return sessions.map((session) => {
const createDate = new Date(session.creationTime!);
const diffDays = Math.floor(
(currentDate.getTime() - createDate.getTime()) / (1000 * 60 * 60 * 24),
);
// 生成原始分组键(用于排序和分组)
let group: string;
if (diffDays < 7) {
group = '7 天内'; // 用数字前缀确保排序正确
}
else if (diffDays < 30) {
group = '30 天内';
}
else {
const year = createDate.getFullYear();
const month = String(createDate.getMonth() + 1).padStart(2, '0');
group = `${year}-${month}`; // 格式2025-05
}
return {
...session,
group, // 新增分组键字段
prefixIcon: markRaw(ChatLineRound), // 图标为静态组件,使用 markRaw 标记为静态组件
};
});
}
return {
// 当前选中的会话
currentSession,
// 设置当前会话
setCurrentSession,
// 列表状态
sessionList,
currentPage,
pageSize,
hasMore,
isLoading,
isLoadingMore,
// 列表方法
createSessionBtn,
createSessionList,
requestSessionList,
loadMoreSessions,
updateSession,
deleteSessions,
};
});