feat: ✨ 新增未登录情况下的处理和添加路由动画
This commit is contained in:
parent
edbb5ec5ba
commit
d15519e18f
@ -13,4 +13,6 @@ VITE_WEB_BASE_API = '/prod-api'
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
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
|
||||
|
||||
|
||||
@ -6,8 +6,10 @@ import { reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { login } from '@/api';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { useSessionStore } from '@/stores/modules/session';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const sessionStore = useSessionStore();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
@ -30,8 +32,10 @@ async function handleSubmit() {
|
||||
res.data.token && userStore.setToken(res.data.token);
|
||||
res.data.userInfo && userStore.setUserInfo(res.data.userInfo);
|
||||
ElMessage.success('登录成功');
|
||||
router.replace('/');
|
||||
userStore.closeLoginDialog();
|
||||
// 立刻获取回话列表
|
||||
await sessionStore.requestSessionList(1, true);
|
||||
router.replace('/');
|
||||
}
|
||||
catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
|
||||
@ -15,4 +15,4 @@ export const COLLAPSE_THRESHOLD: number = 600;
|
||||
export const SIDE_BAR_WIDTH: number = 280;
|
||||
|
||||
// 路由白名单地址[本地存在的路由 staticRouter.ts 中]
|
||||
export const ROUTER_WHITE_LIST: string[] = ['/chat', '/500', '/403', '/404'];
|
||||
export const ROUTER_WHITE_LIST: string[] = ['/chat', '/chat/not_login', '/500', '/403', '/404'];
|
||||
|
||||
@ -18,7 +18,7 @@ const sessionStore = useSessionStore();
|
||||
const sessionId = computed(() => route.params?.id);
|
||||
const conversationsList = computed(() => sessionStore.sessionList);
|
||||
const loadMoreLoading = computed(() => sessionStore.isLoadingMore);
|
||||
const active = computed(() => sessionStore.currentSession?.id);
|
||||
const active = ref<string | undefined>();
|
||||
|
||||
onMounted(async () => {
|
||||
// 获取会话列表
|
||||
@ -28,6 +28,7 @@ onMounted(async () => {
|
||||
const currentSessionRes = await get_session(`${sessionId.value}`);
|
||||
// 通过 ID 查询详情,设置当前会话 (因为有分页)
|
||||
sessionStore.setCurrentSession(currentSessionRes.data);
|
||||
active.value = `${sessionId.value}`;
|
||||
}
|
||||
});
|
||||
|
||||
@ -176,7 +177,8 @@ function handleMenuCommand(command: string, item: ConversationItem<ChatSessionVo
|
||||
:items-style="{
|
||||
marginLeft: '8px',
|
||||
userSelect: 'none',
|
||||
borderRadius: '16px',
|
||||
borderRadius: '10px',
|
||||
padding: '8px 12px',
|
||||
}"
|
||||
:items-active-style="{
|
||||
backgroundColor: '#fff',
|
||||
|
||||
@ -3,8 +3,10 @@
|
||||
import Popover from '@/components/Popover/index.vue';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { useSessionStore } from '@/stores/modules/session';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const sessionStore = useSessionStore();
|
||||
const src = computed(
|
||||
() => userStore.userInfo?.avatar ?? 'https://avatars.githubusercontent.com/u/76239030',
|
||||
);
|
||||
@ -62,9 +64,12 @@ function handleClick(item: any) {
|
||||
roundButton: true,
|
||||
autofocus: false,
|
||||
})
|
||||
.then(() => {
|
||||
.then(async () => {
|
||||
// 在这里执行退出方法
|
||||
userStore.logout();
|
||||
await userStore.logout();
|
||||
// 清空回话列表并回到默认页
|
||||
await sessionStore.requestSessionList(1, true);
|
||||
await sessionStore.createSessionBtn();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '退出成功',
|
||||
|
||||
@ -14,7 +14,7 @@ function handleCreatChat() {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="create-chat-container flex-center flex-none p-6px pl-8px pr-8px c-#0057ff b-#0057ff b-rounded-12px border-1px hover:bg-#0057ff hover:c-#fff hover:b-#fff hover:cursor-pointer border-solid"
|
||||
class="create-chat-container flex-center flex-none p-6px pl-8px pr-8px c-#0057ff b-#0057ff b-rounded-12px border-1px hover:bg-#0057ff hover:c-#fff hover:b-#fff hover:cursor-pointer border-solid select-none"
|
||||
@click="handleCreatChat"
|
||||
>
|
||||
<el-icon size="12" class="flex-center flex-none w-14px h-14px">
|
||||
|
||||
@ -14,6 +14,8 @@ const userStore = useUserStore();
|
||||
const designStore = useDesignStore();
|
||||
const sessionStore = useSessionStore();
|
||||
|
||||
const currentSession = computed(() => sessionStore.currentSession);
|
||||
|
||||
onMounted(() => {
|
||||
// 全局设置侧边栏默认宽度 (这个是不变的,一开始就设置)
|
||||
document.documentElement.style.setProperty(`--sidebar-default-width`, `${SIDE_BAR_WIDTH}px`);
|
||||
@ -55,7 +57,7 @@ onKeyStroke(event => event.ctrlKey && event.key.toLowerCase() === 'k', handleCtr
|
||||
>
|
||||
<Collapse />
|
||||
<CreateChat />
|
||||
<div class="w-0.5px h-30px bg-[rgba(217,217,217)]" />
|
||||
<div v-if="currentSession" class="w-0.5px h-30px bg-[rgba(217,217,217)]" />
|
||||
</div>
|
||||
|
||||
<!-- 中间 -->
|
||||
|
||||
@ -1,10 +1,21 @@
|
||||
<!-- Main -->
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useDesignStore } from '@/stores';
|
||||
import { useKeepAliveStore } from '@/stores/modules/keepAlive';
|
||||
|
||||
const designStore = useDesignStore();
|
||||
const keepAliveStore = useKeepAliveStore();
|
||||
const useroute = useRoute();
|
||||
|
||||
const transitionName = computed(() => {
|
||||
if (useroute.meta.isDefaultChat) {
|
||||
return 'slide';
|
||||
}
|
||||
else {
|
||||
return designStore.pageAnimateType;
|
||||
}
|
||||
});
|
||||
|
||||
// 刷新当前路由页面缓存方法
|
||||
const isRouterShow = ref(true);
|
||||
@ -15,7 +26,7 @@ provide('refresh', refreshMainPage);
|
||||
<template>
|
||||
<el-main class="layout-main">
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition :name="designStore.pageAnimateType" mode="out-in" appear>
|
||||
<transition :name="transitionName" mode="out-in" appear>
|
||||
<keep-alive :max="10" :include="keepAliveStore.keepAliveName">
|
||||
<component :is="Component" v-if="isRouterShow" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
@ -24,4 +35,52 @@ provide('refresh', refreshMainPage);
|
||||
</el-main>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
.layout-main {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 默认聊天页面:上下滑动动画 */
|
||||
.slide-enter-from {
|
||||
margin-top: 200px;
|
||||
opacity: 0;
|
||||
}
|
||||
.slide-enter-active,
|
||||
.slide-leave-active {
|
||||
transition: all 0.3s; /* 缓出动画 */
|
||||
}
|
||||
.slide-enter-to {
|
||||
margin-top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
.slide-leave-from {
|
||||
margin-top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
.slide-leave-to {
|
||||
margin-top: 200px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* 带id聊天页面:中间缩放动画 */
|
||||
.zoom-fade-enter-from {
|
||||
transform: scale(0.8); /* 进入前:缩小隐藏 */
|
||||
opacity: 0;
|
||||
}
|
||||
.zoom-fade-enter-active,
|
||||
.zoom-fade-leave-active {
|
||||
transition: all 0.3s; /* 缓入动画 */
|
||||
}
|
||||
.zoom-fade-enter-to {
|
||||
transform: scale(1); /* 进入后:正常大小 */
|
||||
opacity: 1;
|
||||
}
|
||||
.zoom-fade-leave-from {
|
||||
transform: scale(1); /* 离开前:正常大小 */
|
||||
opacity: 1;
|
||||
}
|
||||
.zoom-fade-leave-to {
|
||||
transform: scale(0.8); /* 离开后:缩小隐藏 */
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -5,7 +5,9 @@ import ChatWithId from '@/pages/chat/layouts/chatWithId/index.vue';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const sessionId = computed(() => Number(route.params?.id));
|
||||
const sessionId = computed(() => route.params?.id);
|
||||
|
||||
console.log(sessionId.value);
|
||||
|
||||
// const a = JSON.parse(`{"id":"chatcmpl-BVD1f4snw4KHOCKIgu4JOMoZbOwRh","object":"chat.completion.chunk","created":1746777939,"model":"gpt-4o-mini-2024-07-18","system_fingerprint":"fp_ded0d14823","choices":[{"delta":{"content":"","role":"assistant"},"logprobs":null,"finish_reason":null,"index":0}],"usage":null}`)
|
||||
// console.log(a);
|
||||
|
||||
@ -13,6 +13,7 @@ const senderValue = ref('');
|
||||
const isDeepThinking = computed(() => chatStore.isDeepThinking);
|
||||
|
||||
async function handleSend() {
|
||||
localStorage.setItem('chatContent', senderValue.value);
|
||||
await sessionStore.createSessionList({
|
||||
userId: userStore.userInfo?.userId as number,
|
||||
sessionContent: senderValue.value,
|
||||
|
||||
@ -14,6 +14,7 @@ export const layoutRouter: RouteRecordRaw[] = [
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
meta: {
|
||||
title: '通用聊天页面',
|
||||
isDefaultChat: true,
|
||||
icon: 'HomeFilled',
|
||||
isHide: '1',
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
@ -27,6 +28,7 @@ export const layoutRouter: RouteRecordRaw[] = [
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
meta: {
|
||||
title: '带 ID 的聊天页面',
|
||||
isDefaultChat: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@ -13,6 +13,9 @@ export const useChatStore = defineStore('chat', () => {
|
||||
};
|
||||
|
||||
const requestChatList = async (sessionId: number) => {
|
||||
// 如果没有 token 则不查询聊天记录
|
||||
if (!userStore.token)
|
||||
return;
|
||||
try {
|
||||
const res = await getChatList({
|
||||
sessionId,
|
||||
|
||||
@ -26,7 +26,7 @@ export const useSessionStore = defineStore('session', () => {
|
||||
// 会话列表核心状态
|
||||
const sessionList = ref<ChatSessionVo[]>([]); // 会话数据列表
|
||||
const currentPage = ref(1); // 当前页码(从1开始)
|
||||
const pageSize = ref(20); // 每页显示数量
|
||||
const pageSize = ref(25); // 每页显示数量
|
||||
const hasMore = ref(true); // 是否还有更多数据
|
||||
const isLoading = ref(false); // 全局加载状态(初始加载/刷新)
|
||||
const isLoadingMore = ref(false); // 加载更多状态(区分初始加载)
|
||||
@ -45,6 +45,12 @@ export const useSessionStore = defineStore('session', () => {
|
||||
|
||||
// 获取会话列表(核心分页方法)
|
||||
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;
|
||||
|
||||
@ -62,13 +68,11 @@ export const useSessionStore = defineStore('session', () => {
|
||||
|
||||
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) }),
|
||||
); // 更新/添加数据
|
||||
res.forEach(item => allSessions.set(item.id, { ...item })); // 更新/添加数据
|
||||
|
||||
// 按服务端排序重建列表(假设分页数据是按时间倒序,第一页是最新,后续页依次递减)
|
||||
// 此处需根据接口返回的排序规则调整,假设每页数据是递增的(第一页最新,第二页次新,第三页 oldest)
|
||||
@ -104,6 +108,16 @@ export const useSessionStore = defineStore('session', () => {
|
||||
|
||||
// 发送消息后创建新会话
|
||||
const createSessionList = async (data: Omit<CreateSessionDTO, 'id'>) => {
|
||||
if (!userStore.token) {
|
||||
router.replace({
|
||||
name: 'chatWithId',
|
||||
params: {
|
||||
id: 'not_login',
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await create_session(data);
|
||||
// 创建会话后立刻查询列表会话
|
||||
@ -202,6 +216,7 @@ export const useSessionStore = defineStore('session', () => {
|
||||
return {
|
||||
...session,
|
||||
group, // 新增分组键字段
|
||||
prefixIcon: markRaw(ChatLineRound), // 图标为静态组件,使用 markRaw 标记为静态组件
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user