feat: ✨ 完善会话管理,新增回话管理详情接口和覆盖修改逻辑
This commit is contained in:
parent
b00380d617
commit
edbb5ec5ba
@ -11,4 +11,6 @@ VITE_WEB_ENV = 'development'
|
|||||||
VITE_WEB_BASE_API = '/dev-api'
|
VITE_WEB_BASE_API = '/dev-api'
|
||||||
|
|
||||||
# 本地接口
|
# 本地接口
|
||||||
VITE_API_URL = http://122.51.75.95:6039
|
# VITE_API_URL = http://122.51.75.95:6039
|
||||||
|
|
||||||
|
VITE_API_URL = http://129.211.24.7:6039
|
||||||
|
|||||||
@ -18,6 +18,10 @@ export function update_session(data: ChatSessionVo) {
|
|||||||
return put('/system/session', data);
|
return put('/system/session', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function get_session(id: string) {
|
||||||
|
return get<ChatSessionVo>(`/system/session/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
export function delete_session(ids: string[]) {
|
export function delete_session(ids: string[]) {
|
||||||
return del(`/system/session/${ids}`);
|
return del(`/system/session/${ids}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,6 +88,10 @@ export interface ChatSessionVo {
|
|||||||
* 用户id
|
* 用户id
|
||||||
*/
|
*/
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
createTime?: Date;
|
||||||
/**
|
/**
|
||||||
* 自定义的消息前缀图标字段
|
* 自定义的消息前缀图标字段
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -122,7 +122,7 @@ function onAfterLeave() {
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
backdrop-filter: blur(3px);
|
backdrop-filter: blur(3px);
|
||||||
z-index: 99999;
|
z-index: 2000;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<!-- 欢迎提示词 -->
|
<!-- 欢迎提示词 -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { Typewriter } from 'vue-element-plus-x';
|
||||||
import { useTimeGreeting } from '@/hooks/useTimeGreeting';
|
import { useTimeGreeting } from '@/hooks/useTimeGreeting';
|
||||||
import { useUserStore } from '@/stores';
|
import { useUserStore } from '@/stores';
|
||||||
|
|
||||||
@ -13,8 +14,23 @@ const username = computed(() => userStore.userInfo?.username ?? '我是 Element
|
|||||||
<div
|
<div
|
||||||
class="welcome-text w-full flex flex-wrap items-center justify-center text-center text-lg font-semibold mb-32px mt-12px font-size-32px line-height-32px"
|
class="welcome-text w-full flex flex-wrap items-center justify-center text-center text-lg font-semibold mb-32px mt-12px font-size-32px line-height-32px"
|
||||||
>
|
>
|
||||||
{{ greeting }}好,{{ username }}
|
<Typewriter
|
||||||
|
:content="`${greeting}好,${username}`"
|
||||||
|
:typing="{
|
||||||
|
step: 2,
|
||||||
|
interval: 45,
|
||||||
|
}"
|
||||||
|
:is-fog="{
|
||||||
|
bgColor: '#fff',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss">
|
||||||
|
:deep {
|
||||||
|
.typer-container {
|
||||||
|
overflow: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<!-- -->
|
<!-- 手机端布局 -->
|
||||||
<script setup></script>
|
<script setup></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
<!-- Aside 侧边栏 -->
|
<!-- Aside 侧边栏 -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ConversationItem, GroupableOptions } from 'vue-element-plus-x/types/Conversations';
|
import type { ConversationItem } from 'vue-element-plus-x/types/Conversations';
|
||||||
import type { ChatSessionVo } from '@/api/session/types';
|
import type { ChatSessionVo } from '@/api/session/types';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { get_session } from '@/api/session';
|
||||||
import logo from '@/assets/images/logo.png';
|
import logo from '@/assets/images/logo.png';
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||||
import Collapse from '@/layouts/components/Header/components/Collapse.vue';
|
import Collapse from '@/layouts/components/Header/components/Collapse.vue';
|
||||||
@ -17,27 +18,16 @@ const sessionStore = useSessionStore();
|
|||||||
const sessionId = computed(() => route.params?.id);
|
const sessionId = computed(() => route.params?.id);
|
||||||
const conversationsList = computed(() => sessionStore.sessionList);
|
const conversationsList = computed(() => sessionStore.sessionList);
|
||||||
const loadMoreLoading = computed(() => sessionStore.isLoadingMore);
|
const loadMoreLoading = computed(() => sessionStore.isLoadingMore);
|
||||||
const active = ref();
|
const active = computed(() => sessionStore.currentSession?.id);
|
||||||
|
|
||||||
// 自定义分组选项
|
|
||||||
const customGroupOptions: GroupableOptions = {
|
|
||||||
// 自定义分组排序,学习 > 工作 > 个人 > 未分组
|
|
||||||
sort: (a: any, b: any) => {
|
|
||||||
const order: Record<string, number> = { 学习: 0, 工作: 1, 个人: 2, 未分组: 3 };
|
|
||||||
const orderA = order[a] !== undefined ? order[a] : 999;
|
|
||||||
const orderB = order[b] !== undefined ? order[b] : 999;
|
|
||||||
return orderA - orderB;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 获取会话列表
|
// 获取会话列表
|
||||||
await sessionStore.requestSessionList();
|
await sessionStore.requestSessionList();
|
||||||
// 高亮最新会话
|
// 高亮最新会话
|
||||||
if (conversationsList.value.length > 0 && sessionId.value) {
|
if (conversationsList.value.length > 0 && sessionId.value) {
|
||||||
active.value = sessionId.value;
|
const currentSessionRes = await get_session(`${sessionId.value}`);
|
||||||
// 通过 ID 查询详情,设置当前会话 (因为有分页)
|
// 通过 ID 查询详情,设置当前会话 (因为有分页)
|
||||||
// sessionStore.currentSession = sessionStore.getSessionById(sessionId.value);
|
sessionStore.setCurrentSession(currentSessionRes.data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,7 +40,6 @@ function handleCreatChat() {
|
|||||||
// 切换会话
|
// 切换会话
|
||||||
function handleChange(item: ConversationItem<ChatSessionVo>) {
|
function handleChange(item: ConversationItem<ChatSessionVo>) {
|
||||||
sessionStore.setCurrentSession(item);
|
sessionStore.setCurrentSession(item);
|
||||||
active.value = item.id;
|
|
||||||
router.replace({
|
router.replace({
|
||||||
name: 'chatWithId',
|
name: 'chatWithId',
|
||||||
params: {
|
params: {
|
||||||
@ -77,6 +66,7 @@ function handleMenuCommand(command: string, item: ConversationItem<ChatSessionVo
|
|||||||
confirmButtonClass: 'el-button--danger',
|
confirmButtonClass: 'el-button--danger',
|
||||||
cancelButtonClass: 'el-button--info',
|
cancelButtonClass: 'el-button--info',
|
||||||
roundButton: true,
|
roundButton: true,
|
||||||
|
autofocus: false,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// 删除会话
|
// 删除会话
|
||||||
@ -101,6 +91,7 @@ function handleMenuCommand(command: string, item: ConversationItem<ChatSessionVo
|
|||||||
cancelButtonClass: 'el-button--info',
|
cancelButtonClass: 'el-button--info',
|
||||||
roundButton: true,
|
roundButton: true,
|
||||||
inputValue: item.sessionTitle, // 设置默认值
|
inputValue: item.sessionTitle, // 设置默认值
|
||||||
|
autofocus: false,
|
||||||
inputValidator: (value) => {
|
inputValidator: (value) => {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return false;
|
return false;
|
||||||
@ -174,11 +165,12 @@ function handleMenuCommand(command: string, item: ConversationItem<ChatSessionVo
|
|||||||
:items="conversationsList"
|
:items="conversationsList"
|
||||||
:label-max-width="200"
|
:label-max-width="200"
|
||||||
:show-tooltip="true"
|
:show-tooltip="true"
|
||||||
:tooltip-offset="35"
|
:tooltip-offset="60"
|
||||||
show-built-in-menu
|
show-built-in-menu
|
||||||
:groupable="customGroupOptions"
|
groupable
|
||||||
row-key="id"
|
row-key="id"
|
||||||
label-key="sessionTitle"
|
label-key="sessionTitle"
|
||||||
|
tooltip-placement="right"
|
||||||
:load-more="handleLoadMore"
|
:load-more="handleLoadMore"
|
||||||
:load-more-loading="loadMoreLoading"
|
:load-more-loading="loadMoreLoading"
|
||||||
:items-style="{
|
:items-style="{
|
||||||
@ -396,6 +388,7 @@ function handleMenuCommand(command: string, item: ConversationItem<ChatSessionVo
|
|||||||
|
|
||||||
// 群组标题样式 和 侧边栏菜单背景色一致
|
// 群组标题样式 和 侧边栏菜单背景色一致
|
||||||
.conversation-group-title {
|
.conversation-group-title {
|
||||||
|
padding-left: 12px !important;
|
||||||
background-color: var(--sidebar-background-color) !important;
|
background-color: var(--sidebar-background-color) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,6 +60,7 @@ function handleClick(item: any) {
|
|||||||
confirmButtonClass: 'el-button--danger',
|
confirmButtonClass: 'el-button--danger',
|
||||||
cancelButtonClass: 'el-button--info',
|
cancelButtonClass: 'el-button--info',
|
||||||
roundButton: true,
|
roundButton: true,
|
||||||
|
autofocus: false,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// 在这里执行退出方法
|
// 在这里执行退出方法
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
<!-- Header 头部 -->
|
<!-- Header 头部 -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { onKeyStroke } from '@vueuse/core';
|
||||||
import { SIDE_BAR_WIDTH } from '@/config/index';
|
import { SIDE_BAR_WIDTH } from '@/config/index';
|
||||||
import { useDesignStore, useUserStore } from '@/stores';
|
import { useDesignStore, useUserStore } from '@/stores';
|
||||||
|
import { useSessionStore } from '@/stores/modules/session';
|
||||||
import Avatar from './components/Avatar.vue';
|
import Avatar from './components/Avatar.vue';
|
||||||
import Collapse from './components/Collapse.vue';
|
import Collapse from './components/Collapse.vue';
|
||||||
import CreateChat from './components/CreateChat.vue';
|
import CreateChat from './components/CreateChat.vue';
|
||||||
@ -10,7 +12,7 @@ import TitleEditing from './components/TitleEditing.vue';
|
|||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const designStore = useDesignStore();
|
const designStore = useDesignStore();
|
||||||
console.log('userStore', userStore.token);
|
const sessionStore = useSessionStore();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 全局设置侧边栏默认宽度 (这个是不变的,一开始就设置)
|
// 全局设置侧边栏默认宽度 (这个是不变的,一开始就设置)
|
||||||
@ -25,6 +27,17 @@ onMounted(() => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 定义 Ctrl+K 的处理函数
|
||||||
|
function handleCtrlK(event: KeyboardEvent) {
|
||||||
|
event.preventDefault(); // 防止默认行为
|
||||||
|
sessionStore.createSessionBtn();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置全局的键盘按键监听
|
||||||
|
onKeyStroke(event => event.ctrlKey && event.key.toLowerCase() === 'k', handleCtrlK, {
|
||||||
|
passive: false,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@ -3,7 +3,13 @@ import { ChatLineRound } from '@element-plus/icons-vue';
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { markRaw } from 'vue';
|
import { markRaw } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { create_session, delete_session, get_session_list, update_session } from '@/api/session';
|
import {
|
||||||
|
create_session,
|
||||||
|
delete_session,
|
||||||
|
get_session,
|
||||||
|
get_session_list,
|
||||||
|
update_session,
|
||||||
|
} from '@/api/session';
|
||||||
import { useUserStore } from './user';
|
import { useUserStore } from './user';
|
||||||
|
|
||||||
export const useSessionStore = defineStore('session', () => {
|
export const useSessionStore = defineStore('session', () => {
|
||||||
@ -28,49 +34,18 @@ export const useSessionStore = defineStore('session', () => {
|
|||||||
// 创建新对话(按钮点击)
|
// 创建新对话(按钮点击)
|
||||||
const createSessionBtn = async () => {
|
const createSessionBtn = async () => {
|
||||||
try {
|
try {
|
||||||
|
// 清空当前选中会话信息
|
||||||
|
setCurrentSession(null);
|
||||||
router.replace({ name: 'chat' });
|
router.replace({ name: 'chat' });
|
||||||
currentSession.value = null;
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('createSessionBtn错误:', error);
|
console.error('createSessionBtn错误:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 发送消息后创建新会话(并插入列表顶部)
|
|
||||||
const createSessionList = async (data: Omit<CreateSessionDTO, 'id'>) => {
|
|
||||||
try {
|
|
||||||
const res = await create_session(data);
|
|
||||||
|
|
||||||
console.log('并插入列表顶部 res', res);
|
|
||||||
|
|
||||||
// 构造新会话对象(根据接口实际返回调整)
|
|
||||||
const newSession: ChatSessionVo = {
|
|
||||||
...data,
|
|
||||||
sessionTitle: data.sessionTitle || '新对话',
|
|
||||||
prefixIcon: markRaw(ChatLineRound),
|
|
||||||
};
|
|
||||||
|
|
||||||
// 插入到列表顶部(触发视图更新)
|
|
||||||
sessionList.value.unshift(newSession);
|
|
||||||
|
|
||||||
// 跳转聊天页
|
|
||||||
router.replace({
|
|
||||||
name: 'chatWithId',
|
|
||||||
params: { id: `${res.data}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
// 重置分页状态(新增会话后,后续加载从第一页重新开始)
|
|
||||||
currentPage.value = 1;
|
|
||||||
hasMore.value = true;
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('createSessionList错误:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取会话列表(核心分页方法)
|
// 获取会话列表(核心分页方法)
|
||||||
const requestSessionList = async (page: number = currentPage.value) => {
|
const requestSessionList = async (page: number = currentPage.value, force: boolean = false) => {
|
||||||
if ((page > 1 && !hasMore.value) || isLoading.value || isLoadingMore.value)
|
if (!force && ((page > 1 && !hasMore.value) || isLoading.value || isLoadingMore.value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
isLoading.value = page === 1; // 第一页时标记为全局加载
|
isLoading.value = page === 1; // 第一页时标记为全局加载
|
||||||
@ -81,37 +56,42 @@ export const useSessionStore = defineStore('session', () => {
|
|||||||
userId: userStore.userInfo?.userId as number,
|
userId: userStore.userInfo?.userId as number,
|
||||||
pageNum: page,
|
pageNum: page,
|
||||||
pageSize: pageSize.value,
|
pageSize: pageSize.value,
|
||||||
|
isAsc: 'desc',
|
||||||
|
orderByColumn: 'createTime',
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await get_session_list(params);
|
const resArr = await get_session_list(params);
|
||||||
|
|
||||||
// 第一页:覆盖原有数据;非第一页:合并新数据
|
// 预处理会话分组
|
||||||
|
const res = processSessions(resArr.rows);
|
||||||
|
|
||||||
|
const allSessions = new Map(sessionList.value.map(item => [item.id, item])); // 现有所有数据
|
||||||
|
res.forEach(item =>
|
||||||
|
allSessions.set(item.id, { ...item, prefixIcon: markRaw(ChatLineRound) }),
|
||||||
|
); // 更新/添加数据
|
||||||
|
|
||||||
|
// 按服务端排序重建列表(假设分页数据是按时间倒序,第一页是最新,后续页依次递减)
|
||||||
|
// 此处需根据接口返回的排序规则调整,假设每页数据是递增的(第一页最新,第二页次新,第三页 oldest)
|
||||||
if (page === 1) {
|
if (page === 1) {
|
||||||
sessionList.value
|
// 第一页是最新数据,应排在列表前面
|
||||||
= res.rows?.map((item: ChatSessionVo) => {
|
sessionList.value = [
|
||||||
return {
|
...res, // 新的第一页数据(最新)
|
||||||
...item,
|
...Array.from(allSessions.values()).filter(item => !res.some(r => r.id === item.id)), // 保留未被第一页覆盖的旧数据
|
||||||
prefixIcon: markRaw(ChatLineRound),
|
];
|
||||||
};
|
|
||||||
}) || [];
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 去重处理(避免接口返回重复数据)
|
// 非第一页数据是更旧的数据,追加到列表末尾
|
||||||
const existingIds = new Set(sessionList.value.map(item => item.id));
|
sessionList.value = [
|
||||||
const newRows = (
|
...sessionList.value.filter(item => !res.some(r => r.id === item.id)), // 保留现有数据(除了被当前页更新的)
|
||||||
res.rows?.map((item: ChatSessionVo) => {
|
...res, // 追加当前页的新数据(更旧的)
|
||||||
return {
|
];
|
||||||
...item,
|
|
||||||
prefixIcon: markRaw(ChatLineRound),
|
|
||||||
};
|
|
||||||
}) || []
|
|
||||||
).filter(item => !existingIds.has(item.id));
|
|
||||||
sessionList.value.push(...newRows);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否还有更多数据(当前页数据量 < pageSize 则无更多)
|
// 判断是否还有更多数据(当前页数据量 < pageSize 则无更多)
|
||||||
hasMore.value = (res.rows?.length || 0) === pageSize.value;
|
if (!force)
|
||||||
currentPage.value = page;
|
hasMore.value = (res?.length || 0) === pageSize.value;
|
||||||
|
if (!force)
|
||||||
|
currentPage.value = page; // 仅非强制刷新时更新页码
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('requestSessionList错误:', error);
|
console.error('requestSessionList错误:', error);
|
||||||
@ -122,6 +102,35 @@ export const useSessionStore = defineStore('session', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 发送消息后创建新会话
|
||||||
|
const createSessionList = async (data: Omit<CreateSessionDTO, 'id'>) => {
|
||||||
|
try {
|
||||||
|
const res = await create_session(data);
|
||||||
|
// 创建会话后立刻查询列表会话
|
||||||
|
// 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}`);
|
||||||
|
setCurrentSession(newSessionRes.data);
|
||||||
|
|
||||||
|
// 跳转聊天页
|
||||||
|
router.replace({
|
||||||
|
name: 'chatWithId',
|
||||||
|
params: { id: `${res.data}` },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('createSessionList错误:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 加载更多会话(供组件调用)
|
// 加载更多会话(供组件调用)
|
||||||
const loadMoreSessions = async () => {
|
const loadMoreSessions = async () => {
|
||||||
if (hasMore.value)
|
if (hasMore.value)
|
||||||
@ -132,7 +141,15 @@ export const useSessionStore = defineStore('session', () => {
|
|||||||
const updateSession = async (item: ChatSessionVo) => {
|
const updateSession = async (item: ChatSessionVo) => {
|
||||||
try {
|
try {
|
||||||
await update_session(item);
|
await update_session(item);
|
||||||
await requestSessionList(currentPage.value);
|
// 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) {
|
catch (error) {
|
||||||
console.error('updateSession错误:', error);
|
console.error('updateSession错误:', error);
|
||||||
@ -143,13 +160,52 @@ export const useSessionStore = defineStore('session', () => {
|
|||||||
const deleteSessions = async (ids: string[]) => {
|
const deleteSessions = async (ids: string[]) => {
|
||||||
try {
|
try {
|
||||||
await delete_session(ids);
|
await delete_session(ids);
|
||||||
await requestSessionList(currentPage.value);
|
// 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) {
|
catch (error) {
|
||||||
console.error('deleteSessions错误:', error);
|
console.error('deleteSessions错误:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 在获取会话列表后添加预处理逻辑(示例)
|
||||||
|
function processSessions(sessions: ChatSessionVo[]) {
|
||||||
|
const currentDate = new Date();
|
||||||
|
|
||||||
|
return sessions.map((session) => {
|
||||||
|
const createDate = new Date(session.createTime!);
|
||||||
|
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, // 新增分组键字段
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// 当前选中的会话
|
// 当前选中的会话
|
||||||
currentSession,
|
currentSession,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { HookFetchPlugin } from 'hook-fetch';
|
|||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import hookFetch from 'hook-fetch';
|
import hookFetch from 'hook-fetch';
|
||||||
import { sseTextDecoderPlugin } from 'hook-fetch/plugins';
|
import { sseTextDecoderPlugin } from 'hook-fetch/plugins';
|
||||||
|
import router from '@/routers';
|
||||||
import { useUserStore } from '@/stores';
|
import { useUserStore } from '@/stores';
|
||||||
|
|
||||||
interface BaseResponse {
|
interface BaseResponse {
|
||||||
@ -33,6 +34,24 @@ function jwtPlugin(): HookFetchPlugin<BaseResponse> {
|
|||||||
if (response.result?.code === 200) {
|
if (response.result?.code === 200) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
// 处理500逻辑
|
||||||
|
if (response.result?.code === 500) {
|
||||||
|
router.replace({
|
||||||
|
name: '500',
|
||||||
|
});
|
||||||
|
ElMessage.error(response.result?.msg);
|
||||||
|
return Promise.reject(response);
|
||||||
|
}
|
||||||
|
// 处理403逻辑
|
||||||
|
if (response.result?.code === 403) {
|
||||||
|
// 跳转到403页面(确保路由已配置)
|
||||||
|
router.replace({
|
||||||
|
name: '403',
|
||||||
|
});
|
||||||
|
ElMessage.error(response.result?.msg);
|
||||||
|
return Promise.reject(response);
|
||||||
|
}
|
||||||
|
// 处理401逻辑
|
||||||
if (response.result?.code === 401) {
|
if (response.result?.code === 401) {
|
||||||
// 如果没有权限,退出,且弹框提示登录
|
// 如果没有权限,退出,且弹框提示登录
|
||||||
userStore.logout();
|
userStore.logout();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user