feat: ✨ 新增路由守卫
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import type {
|
||||
ChatSessionVo,
|
||||
CreateSessionDTO,
|
||||
CreateSessionVO,
|
||||
// CreateSessionVO,
|
||||
GetSessionListParams,
|
||||
} from './types';
|
||||
import { get, post } from '@/utils/request';
|
||||
@@ -11,5 +11,5 @@ export function getSessionList(params: GetSessionListParams) {
|
||||
}
|
||||
|
||||
export function createSession(data: CreateSessionDTO) {
|
||||
return post<CreateSessionVO>('/system/session', data);
|
||||
return post('/system/session', data);
|
||||
}
|
||||
|
||||
@@ -137,6 +137,6 @@ export interface CreateSessionDTO {
|
||||
userId: number;
|
||||
}
|
||||
|
||||
export interface CreateSessionVO {
|
||||
id: number;
|
||||
}
|
||||
// export interface CreateSessionVO {
|
||||
// id: number;
|
||||
// }
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 20 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 24 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 103 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
@@ -5,7 +5,7 @@ import type { LoginDTO } from '@/api/auth/types';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { login } from '@/api';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -29,7 +29,9 @@ async function handleSubmit() {
|
||||
console.log(res, 'res');
|
||||
res.data.token && userStore.setToken(res.data.token);
|
||||
res.data.userInfo && userStore.setUserInfo(res.data.userInfo);
|
||||
ElMessage.success('登录成功');
|
||||
router.replace('/');
|
||||
userStore.closeLoginDialog();
|
||||
}
|
||||
catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
@@ -39,7 +41,7 @@ async function handleSubmit() {
|
||||
|
||||
<template>
|
||||
<div class="custom-form">
|
||||
<el-form ref="formRef" :model="formModel" :rules="rules">
|
||||
<el-form ref="formRef" :model="formModel" :rules="rules" style="width: 230px">
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="formModel.username" placeholder="请输入用户名" clearable>
|
||||
<template #prefix>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ref, watch } from 'vue';
|
||||
import logoPng from '@/assets/images/logo.png';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
import AccountPassword from './components/FormLogin/AccountPassword.vue';
|
||||
import QrCodeLogin from './components/QrCodeLogin/index.vue';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- 欢迎提示词 -->
|
||||
<script setup lang="ts">
|
||||
import { useTimeGreeting } from '@/hooks/useTimeGreeting';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const greeting = useTimeGreeting();
|
||||
const userStore = useUserStore();
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
export const HOME_URL: string = '/chat';
|
||||
|
||||
// 登录页地址[默认]
|
||||
export const LOGIN_URL: string = '/login';
|
||||
// export const LOGIN_URL: string = '/login';
|
||||
|
||||
// 默认主题颜色
|
||||
export const DEFAULT_THEME_COLOR: string = '#2992FF';
|
||||
@@ -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[] = ['/500'];
|
||||
export const ROUTER_WHITE_LIST: string[] = ['/chat', '/500', '/403', '/404'];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { COLLAPSE_THRESHOLD } from '@/config/index';
|
||||
import { useWindowWidthObserver } from '@/hooks/useWindowWidthObserver';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
/**
|
||||
* 侧边栏折叠切换逻辑组合式函数 方便多个页面调用
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { MaybeRef } from 'vue';
|
||||
import { onBeforeUnmount, ref, unref, watch } from 'vue';
|
||||
import { COLLAPSE_THRESHOLD, SIDE_BAR_WIDTH } from '@/config/index';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
/**
|
||||
* 这里逻辑是研究豆包的折叠逻辑后,设计的折叠方法
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useWindowWidthObserver } from '@/hooks/useWindowWidthObserver';
|
||||
import Aside from '@/layouts/components/Aside/index.vue';
|
||||
import Header from '@/layouts/components/Header/index.vue';
|
||||
import Main from '@/layouts/components/Main/index.vue';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
const designStore = useDesignStore();
|
||||
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
<!-- Aside 侧边栏 -->
|
||||
<script setup lang="ts">
|
||||
import type { GroupableOptions } from 'vue-element-plus-x/types/Conversations';
|
||||
import { useRoute } from 'vue-router';
|
||||
import type { ConversationItem, GroupableOptions } from 'vue-element-plus-x/types/Conversations';
|
||||
import type { ChatSessionVo } from '@/api/session/types';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import logo from '@/assets/images/logo.png';
|
||||
import Collapse from '@/layouts/components/Header/components/Collapse.vue';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useChatStore } from '@/store/modules/chat';
|
||||
import { useDesignStore } from '@/stores';
|
||||
import { useSessionStore } from '@/stores/modules/session';
|
||||
|
||||
const route = useRoute();
|
||||
const chatStore = useChatStore();
|
||||
const router = useRouter();
|
||||
const designStore = useDesignStore();
|
||||
const sessionStore = useSessionStore();
|
||||
|
||||
const chatId = computed(() => Number(route.params?.id));
|
||||
const conversationsList = computed(() => chatStore.chatMap[chatId.value] ?? []);
|
||||
// const sessionId = computed(() => Number(route.params?.id));
|
||||
const conversationsList = computed(() => sessionStore.sessionList);
|
||||
|
||||
/* 创建会话 开始 */
|
||||
function handleCreatChat() {
|
||||
console.log('创建新会话');
|
||||
// 创建会话, 跳转到默认聊天
|
||||
sessionStore.createSessionBtn();
|
||||
}
|
||||
/* 创建会话 结束 */
|
||||
|
||||
/* 会话组件 开始 */
|
||||
const active = ref('m1');
|
||||
const active = computed<string>(() => (route.params?.id as string) ?? '');
|
||||
|
||||
// 自定义分组选项
|
||||
const customGroupOptions: GroupableOptions = {
|
||||
@@ -34,10 +38,20 @@ const customGroupOptions: GroupableOptions = {
|
||||
},
|
||||
};
|
||||
|
||||
function handleChange() {
|
||||
console.log('点击了会话');
|
||||
function handleChange(item: ConversationItem<ChatSessionVo>) {
|
||||
console.log('点击了会话 item', item);
|
||||
router.replace({
|
||||
name: 'chatWithId',
|
||||
params: {
|
||||
id: item.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
/* 会话组件 结束 */
|
||||
|
||||
watchEffect(() => {
|
||||
console.log('active', active.value, '>>>');
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
<script setup lang="ts">
|
||||
import Popover from '@/components/Popover/index.vue';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const src = ref('https://avatars.githubusercontent.com/u/76239030');
|
||||
const userStore = useUserStore();
|
||||
const src = computed(
|
||||
() => userStore.userInfo?.avatar ?? 'https://avatars.githubusercontent.com/u/76239030',
|
||||
);
|
||||
|
||||
/* 弹出面板 开始 */
|
||||
const popoverStyle = ref({
|
||||
@@ -40,9 +44,11 @@ const popoverList = ref([
|
||||
function handleClick(item: any) {
|
||||
switch (item.key) {
|
||||
case '1':
|
||||
ElMessage.warning('暂未开放');
|
||||
console.log('点击了收藏夹');
|
||||
break;
|
||||
case '2':
|
||||
ElMessage.warning('暂未开放');
|
||||
console.log('点击了设置');
|
||||
break;
|
||||
case '4':
|
||||
@@ -57,7 +63,7 @@ function handleClick(item: any) {
|
||||
})
|
||||
.then(() => {
|
||||
// 在这里执行退出方法
|
||||
|
||||
userStore.logout();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '退出成功',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { SIDE_BAR_WIDTH } from '@/config/index';
|
||||
import { useCollapseToggle } from '@/hooks/useCollapseToggle';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
const { changeCollapse } = useCollapseToggle();
|
||||
const designStore = useDesignStore();
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<!-- LoginBtn 登录按钮 -->
|
||||
<script setup lang="ts">
|
||||
import LoginDialog from '@/components/LoginDialog/index.vue';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const isLoginDialogVisible = computed(() => userStore.isLoginDialogVisible);
|
||||
|
||||
// 点击登录按钮时调用Store方法打开弹框
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- Header 头部 -->
|
||||
<script setup lang="ts">
|
||||
import { SIDE_BAR_WIDTH } from '@/config/index';
|
||||
import { useDesignStore, useUserStore } from '@/store';
|
||||
import { useDesignStore, useUserStore } from '@/stores';
|
||||
import Avatar from './components/Avatar.vue';
|
||||
import Collapse from './components/Collapse.vue';
|
||||
import CreateChat from './components/CreateChat.vue';
|
||||
@@ -54,10 +54,8 @@ onMounted(() => {
|
||||
|
||||
<!-- 右边 -->
|
||||
<div class="right-box flex h-full items-center pr-20px flex-shrink-0 mr-auto flex-row">
|
||||
<Avatar v-if="userStore.token" />
|
||||
<LoginBtn v-else />
|
||||
<!-- <Avatar />
|
||||
<LoginBtn /> -->
|
||||
<Avatar v-show="userStore.token" />
|
||||
<LoginBtn v-show="!userStore.token" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- Main -->
|
||||
<script setup lang="ts">
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useKeepAliveStore } from '@/store/modules/keepAlive';
|
||||
import { useDesignStore } from '@/stores';
|
||||
import { useKeepAliveStore } from '@/stores/modules/keepAlive';
|
||||
|
||||
const designStore = useDesignStore();
|
||||
const keepAliveStore = useKeepAliveStore();
|
||||
@@ -16,7 +16,7 @@ provide('refresh', refreshMainPage);
|
||||
<el-main class="layout-main">
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition :name="designStore.pageAnimateType" mode="out-in" appear>
|
||||
<keep-alive :max="16" :include="keepAliveStore.keepAliveName">
|
||||
<keep-alive :max="10" :include="keepAliveStore.keepAliveName">
|
||||
<component :is="Component" v-if="isRouterShow" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ConversationItem } from 'vue-element-plus-x/types/Conversations';
|
||||
import type { ChatSessionVo } from '@/api/session/types';
|
||||
// import { useUserStore } from '@/store';
|
||||
// import { useUserStore } from '@/stores';
|
||||
import { Conversations } from 'vue-element-plus-x';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
// import { getSessionList } from '@/api';
|
||||
@@ -43,13 +43,13 @@ function handleChange(item: ConversationItem<ChatSessionVo>) {
|
||||
const sessionId = computed<string>(() => route.params?.id as string);
|
||||
function handleNewSession() {
|
||||
if (sessionId.value) {
|
||||
router.replace({ name: 'chatWithoutId' });
|
||||
router.replace({ name: 'chatWithId' });
|
||||
}
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
console.log('active', active.value, '>>>');
|
||||
});
|
||||
// watchEffect(() => {
|
||||
// console.log('active', active.value, '>>>');
|
||||
// });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import type { LayoutType } from '@/config/design';
|
||||
// import { useScreenStore } from '@/hooks/useScreen';
|
||||
import LayoutVertical from '@/layouts/LayoutVertical/index.vue';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
// 这里添加布局类型
|
||||
const LayoutComponent: Record<LayoutType, Component> = {
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ import { ElMessage } from 'element-plus';
|
||||
import { createApp } from 'vue';
|
||||
import ElementPlusX from 'vue-element-plus-x';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import router from './routers';
|
||||
import store from './stores';
|
||||
import './styles/index.scss';
|
||||
import 'virtual:uno.css';
|
||||
import 'element-plus/dist/index.css';
|
||||
|
||||
+12
-112
@@ -1,20 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { Sender } from 'vue-element-plus-x';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { createSession } from '@/api';
|
||||
import { send } from '@/api/chat';
|
||||
import WelecomeText from '@/components/WelecomeText/index.vue';
|
||||
import { ModelEnum } from '@/constants/enums';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useChatStore } from '@/store/modules/chat';
|
||||
import { useRoute } from 'vue-router';
|
||||
import ChatDefaul from '@/pages/chat/layouts/chatDefaul/index.vue';
|
||||
import ChatWithId from '@/pages/chat/layouts/chatWithId/index.vue';
|
||||
import { useChatStore } from '@/stores/modules/chat';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const chatStore = useChatStore();
|
||||
|
||||
const senderValue = ref('');
|
||||
const isSelect = ref(false);
|
||||
|
||||
const chatId = computed(() => Number(route.params?.id));
|
||||
if (chatId.value) {
|
||||
@@ -30,107 +23,28 @@ watch(
|
||||
senderValue.value = v;
|
||||
localStorage.removeItem('chatContent');
|
||||
// 发送消息
|
||||
console.log(v);
|
||||
console.log('发送消息 v', v);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
// 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);
|
||||
const loading = ref(false);
|
||||
async function handleSend() {
|
||||
if (!chatId.value) {
|
||||
try {
|
||||
const res = await createSession({
|
||||
userId: userStore.userInfo?.userId as number,
|
||||
sessionContent: senderValue.value,
|
||||
sessionTitle: senderValue.value.slice(0, 10),
|
||||
remark: senderValue.value.slice(0, 10),
|
||||
});
|
||||
localStorage.setItem('chatContent', senderValue.value);
|
||||
router.replace({
|
||||
name: 'chat',
|
||||
params: {
|
||||
id: res.data.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('createSessionError', error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 发送消息
|
||||
loading.value = true;
|
||||
const req = send({
|
||||
sessionId: chatId.value,
|
||||
model: ModelEnum.GPT_4o_MINI.value,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: senderValue.value,
|
||||
},
|
||||
],
|
||||
});
|
||||
for await (const chunk of req) {
|
||||
if (chunk.result && typeof chunk.result === 'string') {
|
||||
console.log('string:', chunk.result);
|
||||
// const a = JSON.parse(chunk.result);
|
||||
// console.log(a,'>>>');
|
||||
}
|
||||
console.log(chunk.result);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="chat-home-container">
|
||||
<div class="chat-home-wrap">
|
||||
<WelecomeText />
|
||||
<Sender
|
||||
v-model="senderValue"
|
||||
class="chat-home-sender"
|
||||
:auto-size="{
|
||||
maxRows: 9,
|
||||
minRows: 3,
|
||||
}"
|
||||
:loading="loading"
|
||||
variant="updown"
|
||||
clearable
|
||||
allow-speech
|
||||
@submit="handleSend"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
||||
<div
|
||||
class="flex items-center gap-4px px-12px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||
>
|
||||
<el-icon>
|
||||
<Paperclip />
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="{ isSelect }"
|
||||
class="flex items-center gap-4px px-10px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||
@click="isSelect = !isSelect"
|
||||
>
|
||||
<el-icon>
|
||||
<ElementPlus />
|
||||
</el-icon>
|
||||
<span>深度思考</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Sender>
|
||||
</div>
|
||||
<div class="chat-container">
|
||||
<!-- 默认聊天页面 -->
|
||||
<ChatDefaul v-if="!chatId" />
|
||||
<!-- 带id的聊天页面 -->
|
||||
<ChatWithId v-else :chat-id="chatId" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chat-home-container {
|
||||
.chat-container {
|
||||
padding: 0 16px;
|
||||
width: calc(100% - 32px);
|
||||
position: relative;
|
||||
@@ -140,19 +54,5 @@ async function handleSend() {
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
overflow-anchor: none;
|
||||
|
||||
.chat-home-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
min-height: 450px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.chat-home-sender {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<!-- -->
|
||||
<script setup lang="ts">
|
||||
import WelecomeText from '@/components/WelecomeText/index.vue';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { useChatStore } from '@/stores/modules/chat';
|
||||
import { useSessionStore } from '@/stores/modules/session';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const chatStore = useChatStore();
|
||||
const sessionStore = useSessionStore();
|
||||
const senderValue = ref('');
|
||||
|
||||
const isDeepThinking = computed(() => chatStore.isDeepThinking);
|
||||
|
||||
async function handleSend() {
|
||||
await sessionStore.createSessionList({
|
||||
userId: userStore.userInfo?.userId as number,
|
||||
sessionContent: senderValue.value,
|
||||
sessionTitle: senderValue.value.slice(0, 10),
|
||||
remark: senderValue.value.slice(0, 10),
|
||||
});
|
||||
}
|
||||
|
||||
// 设置是否深度思考
|
||||
function setIsDeepThinking() {
|
||||
chatStore.setDeepThinking(!chatStore.isDeepThinking);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="chat-defaul-wrap">
|
||||
<WelecomeText />
|
||||
<Sender
|
||||
v-model="senderValue"
|
||||
class="chat-defaul-sender"
|
||||
:auto-size="{
|
||||
maxRows: 9,
|
||||
minRows: 3,
|
||||
}"
|
||||
variant="updown"
|
||||
clearable
|
||||
allow-speech
|
||||
@submit="handleSend"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
||||
<div
|
||||
class="flex items-center gap-4px px-12px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||
>
|
||||
<el-icon>
|
||||
<Paperclip />
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="{ 'is-select': isDeepThinking }"
|
||||
class="flex items-center gap-4px px-10px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||
@click="setIsDeepThinking"
|
||||
>
|
||||
<el-icon>
|
||||
<ElementPlus />
|
||||
</el-icon>
|
||||
<span>深度思考</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Sender>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.chat-defaul-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
min-height: 450px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.chat-defaul-sender {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.is-select {
|
||||
color: var(--el-color-primary, #409eff);
|
||||
border: 1px solid var(--el-color-primary, #409eff);
|
||||
border-radius: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!-- 每个回话对应的聊天内容 -->
|
||||
<script setup lang="ts">
|
||||
interface ChatWithIdProps {
|
||||
chatId?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<ChatWithIdProps>(), {
|
||||
chatId: undefined,
|
||||
});
|
||||
|
||||
console.log('props ==> ', props);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>新建对话</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -0,0 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HOME_URL } from '@/config/index.ts';
|
||||
|
||||
// 路由跳转
|
||||
const router = useRouter();
|
||||
|
||||
function handleHomePage() {
|
||||
router.push({ path: HOME_URL });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="box">
|
||||
<div id="banner" class="elx-top" />
|
||||
<div class="elx-bottom">
|
||||
<div class="elx-text1">
|
||||
403
|
||||
</div>
|
||||
<div class="elx-text2">
|
||||
对不起,您没有权限访问
|
||||
</div>
|
||||
<div class="h-20px" />
|
||||
<el-button type="primary" plain @click="handleHomePage">
|
||||
返回首页
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#banner {
|
||||
margin-top: 60px;
|
||||
background: url("@/assets/images/error/403.png") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.elx-top {
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.elx-bottom {
|
||||
height: 300px;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.elx-text1 {
|
||||
font-size: 46px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.elx-text2 {
|
||||
padding-top: 30px;
|
||||
font-family: YouYuan;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HOME_URL } from '@/config/index.ts';
|
||||
|
||||
// 路由跳转
|
||||
const router = useRouter();
|
||||
|
||||
function handleHomePage() {
|
||||
router.push({ path: HOME_URL });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="box">
|
||||
<div id="banner" class="elx-top" />
|
||||
<div class="elx-bottom">
|
||||
<div class="elx-text1">
|
||||
404
|
||||
</div>
|
||||
<div class="elx-text2">
|
||||
您想看的页面不存在哟
|
||||
</div>
|
||||
<div class="h-20px" />
|
||||
<el-button type="primary" plain @click="handleHomePage">
|
||||
返回首页
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#banner {
|
||||
margin-top: 60px;
|
||||
background: url("@/assets/images/error/404.png") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.elx-top {
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.elx-bottom {
|
||||
height: 300px;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.elx-text1 {
|
||||
font-size: 46px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.elx-text2 {
|
||||
padding-top: 30px;
|
||||
font-family: YouYuan;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,60 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HOME_URL } from '@/config/index.ts';
|
||||
|
||||
// 路由跳转
|
||||
const router = useRouter();
|
||||
|
||||
function handleHomePage() {
|
||||
router.push({ path: HOME_URL });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="box">
|
||||
<div id="banner" class="elx-top" />
|
||||
<div class="elx-bottom">
|
||||
<div class="elx-text1">
|
||||
500
|
||||
</div>
|
||||
<div class="elx-text2">
|
||||
服务器好像开小差了!请稍后试试...
|
||||
</div>
|
||||
<div class="h-20px" />
|
||||
<el-button type="primary" plain @click="handleHomePage">
|
||||
返回首页
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#box {
|
||||
overflow: hidden;
|
||||
}
|
||||
#banner {
|
||||
margin-top: 60px;
|
||||
background: url("@/assets/images/error/500.png") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
.elx-top {
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.elx-bottom {
|
||||
height: 300px;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.elx-text1 {
|
||||
font-size: 46px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.elx-text2 {
|
||||
padding-top: 30px;
|
||||
font-family: YouYuan;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -1,53 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import type { LoginDTO } from '@/api/auth/types';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { login } from '@/api';
|
||||
import { useUserStore } from '@/store';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
const formModel = reactive<LoginDTO>({
|
||||
username: '',
|
||||
password: '',
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
await formRef.value?.validate();
|
||||
const res = await login(formModel);
|
||||
console.log(res, 'res');
|
||||
res.data.token && userStore.setToken(res.data.token);
|
||||
res.data.userInfo && userStore.setUserInfo(res.data.userInfo);
|
||||
router.replace('/');
|
||||
}
|
||||
catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-screen h-screen justify-center items-center flex bg-black">
|
||||
<div class="max-w-[500px] w-full p-5 rounded bg-white/60 backdrop-blur-md">
|
||||
<h1>登录</h1>
|
||||
<el-form ref="formRef" :model="formModel">
|
||||
<el-form-item label="用户名" name="username">
|
||||
<el-input v-model="formModel.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" name="password">
|
||||
<el-input v-model="formModel.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSubmit">
|
||||
登录
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,41 +0,0 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { jwtGuard } from './permissions';
|
||||
|
||||
const routes: Readonly<RouteRecordRaw>[] = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: 'chat',
|
||||
component: () => import('@/layouts/index.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/chat',
|
||||
name: 'chat',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/chat:id',
|
||||
name: 'chatWithoutId',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import('@/pages/login/index.vue'),
|
||||
},
|
||||
] as const;
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
console.group('Routes');
|
||||
console.log('routes', router.getRoutes());
|
||||
console.groupEnd();
|
||||
|
||||
router.beforeEach(jwtGuard());
|
||||
|
||||
export default router;
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { NavigationGuard } from 'vue-router';
|
||||
|
||||
export function jwtGuard(): NavigationGuard {
|
||||
return () => {
|
||||
console.log('进入路由守卫');
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
|
||||
import { useNProgress } from '@vueuse/integrations/useNProgress';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { ROUTER_WHITE_LIST } from '@/config';
|
||||
import { errorRouter, layoutRouter, staticRouter } from '@/routers/modules/staticRouter';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const { start, done } = useNProgress(0, {
|
||||
showSpinner: false,
|
||||
trickleSpeed: 200,
|
||||
minimum: 0.3,
|
||||
easing: 'ease',
|
||||
speed: 500,
|
||||
});
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [...layoutRouter, ...staticRouter, ...errorRouter],
|
||||
strict: false,
|
||||
scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||
});
|
||||
|
||||
console.group('Routes');
|
||||
console.log('routes', router.getRoutes());
|
||||
console.groupEnd();
|
||||
|
||||
// 路由前置守卫
|
||||
router.beforeEach(
|
||||
async (
|
||||
to: RouteLocationNormalized,
|
||||
_from: RouteLocationNormalized,
|
||||
next: NavigationGuardNext,
|
||||
) => {
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 1、NProgress 开始
|
||||
start();
|
||||
|
||||
// 2、标题
|
||||
document.title = to.meta.title || import.meta.env.VITE_WEB_TITLE;
|
||||
|
||||
// 3、权限 预留
|
||||
// 3、判断是访问登陆页,有Token访问当前页面,token过期访问接口,axios封装则自动跳转登录页面,没有Token重置路由到登陆页。
|
||||
// if (to.path.toLocaleLowerCase() === LOGIN_URL) {
|
||||
// // 有Token访问当前页面
|
||||
// if (userStore.token) {
|
||||
// return next(from.fullPath);
|
||||
// }
|
||||
// else {
|
||||
// ElMessage.error('账号身份已过期,请重新登录🌻');
|
||||
// }
|
||||
// // 没有Token重置路由到登陆页。
|
||||
// // resetRouter(); // 预留
|
||||
// return next();
|
||||
// }
|
||||
|
||||
// 4、判断访问页面是否在路由白名单地址[静态路由]中,如果存在直接放行。
|
||||
if (ROUTER_WHITE_LIST.includes(to.path))
|
||||
return next();
|
||||
|
||||
// 5、判断是否有 Token,没有重定向到 login 页面。
|
||||
if (!userStore.token)
|
||||
userStore.logout();
|
||||
|
||||
// 其余逻辑 预留...
|
||||
|
||||
// 6、正常访问页面。
|
||||
next();
|
||||
},
|
||||
);
|
||||
|
||||
// 路由跳转错误
|
||||
router.onError((error) => {
|
||||
// 结束全屏动画
|
||||
done();
|
||||
console.warn('路由错误', error.message);
|
||||
});
|
||||
|
||||
// 后置路由
|
||||
router.afterEach(() => {
|
||||
// 结束全屏动画
|
||||
done();
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,39 @@
|
||||
// 预留
|
||||
import router from '@/routers/index';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { useAuthStore } from '@/stores/modules/auth';
|
||||
|
||||
export async function initDynamicRouter() {
|
||||
const userStore = useUserStore();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
try {
|
||||
// 1、预留: 获取菜单列表 || 按钮权限列表 || 递归菜单数据
|
||||
await authStore.requestAuthMenuList();
|
||||
|
||||
// 2、判断当前用户是否拥有菜单权限
|
||||
console.log('authStore.authMenuList', authStore.authMenuList);
|
||||
|
||||
if (authStore.authMenuList == null || authStore.authMenuList.length === 0) {
|
||||
userStore.logout();
|
||||
return;
|
||||
}
|
||||
|
||||
// 3、添加动态路由
|
||||
authStore.authMenuList.forEach((item: any) => {
|
||||
if (item.isFull === '0') {
|
||||
// 如果是全屏的话,直接为整个页面
|
||||
router.addRoute(item);
|
||||
}
|
||||
else {
|
||||
router.addRoute('layout', item);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
// 当菜单请求出错时,重定向到首页
|
||||
userStore.logout();
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { HOME_URL } from '@/config';
|
||||
|
||||
// LayoutRouter[布局路由]
|
||||
export const layoutRouter: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: HOME_URL,
|
||||
component: () => import('@/layouts/index.vue'),
|
||||
children: [
|
||||
{
|
||||
path: HOME_URL,
|
||||
name: 'chat',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
meta: {
|
||||
title: '通用聊天页面',
|
||||
icon: 'HomeFilled',
|
||||
isHide: '1',
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
isFull: '1', // 是否缓存全屏[0是,1否]
|
||||
// enName: "Master Station", // 英文名称 预留
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/chat/:id',
|
||||
name: 'chatWithId',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
meta: {
|
||||
title: '带 ID 的聊天页面',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
// staticRouter[静态路由] 预留
|
||||
export const staticRouter: RouteRecordRaw[] = [];
|
||||
|
||||
// errorRouter (错误页面路由)
|
||||
export const errorRouter = [
|
||||
{
|
||||
path: '/403',
|
||||
name: '403',
|
||||
component: () => import('@/pages/error/403.vue'),
|
||||
meta: {
|
||||
title: '403页面',
|
||||
enName: '403 Page', // 英文名称
|
||||
icon: 'QuestionFilled', // 菜单图标
|
||||
isHide: '1', // 代表路由在菜单中是否隐藏,是否隐藏[0隐藏,1显示]
|
||||
isLink: '1', // 是否外链[有值则是外链]
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
isFull: '1', // 是否缓存全屏[0是,1否]
|
||||
isAffix: '1', // 是否缓存固定路由[0是,1否]
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
name: '404',
|
||||
component: () => import('@/pages/error/404.vue'),
|
||||
meta: {
|
||||
title: '404页面',
|
||||
enName: '404 Page', // 英文名称
|
||||
icon: 'CircleCloseFilled', // 菜单图标
|
||||
isHide: '1', // 代表路由在菜单中是否隐藏,是否隐藏[0隐藏,1显示]
|
||||
isLink: '1', // 是否外链[有值则是外链]
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
isFull: '1', // 是否缓存全屏[0是,1否]
|
||||
isAffix: '1', // 是否缓存固定路由[0是,1否]
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/500',
|
||||
name: '500',
|
||||
component: () => import('@/pages/error/500.vue'),
|
||||
meta: {
|
||||
title: '500页面',
|
||||
enName: '500 Page', // 英文名称
|
||||
icon: 'WarningFilled', // 图标
|
||||
isHide: '1', // 代表路由在菜单中是否隐藏,是否隐藏[0隐藏,1显示]
|
||||
isLink: '1', // 是否外链[有值则是外链]
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
isFull: '1', // 是否缓存全屏[0是,1否]
|
||||
isAffix: '1', // 是否缓存固定路由[0是,1否]
|
||||
},
|
||||
},
|
||||
// 找不到path将跳转404页面
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
component: () => import('@/pages/error/404.vue'),
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
// 权限状态管理
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
// 权限菜单列表
|
||||
const authMenuList = ref<any[]>([]);
|
||||
|
||||
// 请求权限菜单列表
|
||||
const requestAuthMenuList = async () => {
|
||||
// const res = await initDynamicRouter();
|
||||
authMenuList.value = [];
|
||||
};
|
||||
|
||||
return {
|
||||
authMenuList,
|
||||
requestAuthMenuList,
|
||||
};
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import { useUserStore } from './user';
|
||||
|
||||
export const useChatStore = defineStore('chat', () => {
|
||||
const userStore = useUserStore();
|
||||
|
||||
const chatMap = ref<Record<number, ChatMessageVo[]>>({});
|
||||
|
||||
const setChatMap = (id: number, data: ChatMessageVo[]) => {
|
||||
@@ -26,8 +27,17 @@ export const useChatStore = defineStore('chat', () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 是否开启深度思考
|
||||
const isDeepThinking = ref<boolean>(false);
|
||||
|
||||
const setDeepThinking = (value: boolean) => {
|
||||
isDeepThinking.value = value;
|
||||
};
|
||||
|
||||
return {
|
||||
chatMap,
|
||||
requestChatList,
|
||||
isDeepThinking,
|
||||
setDeepThinking,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import type { CreateSessionDTO } from '@/api/session/types';
|
||||
import { defineStore } from 'pinia';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { createSession, getSessionList } from '@/api/session';
|
||||
import { useUserStore } from './user';
|
||||
|
||||
export const useSessionStore = defineStore('session', () => {
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const sessionList = ref<CreateSessionDTO[]>([]);
|
||||
|
||||
// 单独点击创建新对话按钮
|
||||
const createSessionBtn = async () => {
|
||||
try {
|
||||
// 直接回到首页
|
||||
router.replace({ name: 'chat' });
|
||||
}
|
||||
catch (error) {
|
||||
console.error('createSessionBtn:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 发送消息后,创建对话
|
||||
const createSessionList = async (data: CreateSessionDTO) => {
|
||||
try {
|
||||
const res = await createSession(data);
|
||||
localStorage.setItem('chatContent', data.sessionContent);
|
||||
router.replace({
|
||||
name: 'chatWithId',
|
||||
params: {
|
||||
id: `${res.data}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('createSession:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取会话列表
|
||||
const requestSessionList = async () => {
|
||||
try {
|
||||
const res = await getSessionList({
|
||||
userId: userStore.userInfo?.userId as number,
|
||||
});
|
||||
if (res.rows) {
|
||||
sessionList.value = (res.rows || []).map(item => ({
|
||||
...item,
|
||||
// 提供默认值
|
||||
remark: item.remark || '',
|
||||
sessionContent: item.sessionContent || '',
|
||||
sessionTitle: item.sessionTitle || '',
|
||||
userId: item.userId || -1,
|
||||
}));
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('getSessionList:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
sessionList,
|
||||
createSessionBtn,
|
||||
createSessionList,
|
||||
requestSessionList,
|
||||
};
|
||||
});
|
||||
@@ -16,4 +16,9 @@
|
||||
--login-dialog-logo-background: #fff;
|
||||
--login-dialog-logo-text-color: #191919;
|
||||
|
||||
|
||||
|
||||
/* 覆盖 element-plus 样式 */
|
||||
--el-border-radius-base: 12px;
|
||||
--el-messagebox-border-radius: 16px;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { HookFetchPlugin } from 'hook-fetch';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import hookFetch from 'hook-fetch';
|
||||
import { sseTextDecoderPlugin } from 'hook-fetch/plugins';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
interface BaseResponse {
|
||||
code: number;
|
||||
@@ -34,8 +34,9 @@ function jwtPlugin(): HookFetchPlugin<BaseResponse> {
|
||||
return response;
|
||||
}
|
||||
if (response.result?.code === 401) {
|
||||
// 如果没有权限,也不退出,则是弹框提示登录
|
||||
// 如果没有权限,退出,且弹框提示登录
|
||||
userStore.logout();
|
||||
userStore.openLoginDialog();
|
||||
}
|
||||
ElMessage.error(response.result?.msg);
|
||||
return Promise.reject(response);
|
||||
|
||||
Reference in New Issue
Block a user