feat: 阻止未登录用户使用任何功能

This commit is contained in:
肖应宇 2026-03-09 14:25:38 +08:00
parent ec96a424c4
commit 3421d0db47
7 changed files with 51 additions and 18 deletions

View File

@ -52,6 +52,7 @@ import { ref, computed, watch, nextTick, onMounted } from "vue";
import { storeToRefs } from "pinia";
import { useChatStore } from "@/stores/chat";
import { useSettingsStore } from "@/stores/settings";
import { useAuthStore } from "@/stores/auth";
import ChatHeader from "./ChatHeader.vue";
import MessageList from "./MessageList.vue";
import ChatInput from "@/components/input/ChatInput.vue";
@ -65,6 +66,7 @@ defineEmits<{
const chatStore = useChatStore();
const settingsStore = useSettingsStore();
const authStore = useAuthStore();
const { currentConversation, isStreaming } = storeToRefs(chatStore);
const { settings, sidebarCollapsed } = storeToRefs(settingsStore);
@ -164,6 +166,12 @@ async function handleSend(
systemPrompt?: string;
},
) {
//
if (!authStore.isAuthenticated) {
window.$toast?.('请先登录', 'error');
return;
}
console.log("handleSend", text, attachments, options);
//
const uploadingAttachments = attachments.filter((a) => a.uploading);
@ -337,6 +345,12 @@ function handleStop() {
//
async function handleRetry(messageId: string) {
//
if (!authStore.isAuthenticated) {
window.$toast?.('请先登录', 'error');
return;
}
const message = messages.value.find((m: any) => m.id === messageId);
if (!message || message.role !== MessageRole.ASSISTANT) return;

View File

@ -173,6 +173,7 @@ import AttachmentPreview from "./AttachmentPreview.vue";
import { generateId } from "@/utils/helpers";
import type { Attachment } from "@/types/chat";
import { chatApi } from "@/services/api";
import { useAuthStore } from "@/stores/auth";
interface AttachmentWithProgress extends Attachment {
uploading?: boolean;
@ -216,6 +217,8 @@ const emit = defineEmits<{
}>();
//
const authStore = useAuthStore();
const inputText = ref("");
const attachments = ref<AttachmentWithProgress[]>([]);
const isFocused = ref(false);
@ -350,6 +353,12 @@ async function addFileAsAttachment(
file: File,
type: "image" | "file" | "video",
) {
//
if (!authStore.isAuthenticated) {
window.$toast?.('请先登录', 'error');
return;
}
const id = generateId();
// URL

View File

@ -2,6 +2,8 @@
* Chat UI API
*
*/
import { getAuthHeaders } from './request';
// API 端点定义(固定)
const API_ENDPOINTS = {
// 发送消息(流式)
@ -153,7 +155,7 @@ class ChatApi {
{
method: "POST",
headers: {
"Content-Type": "application/json",
...getAuthHeaders(),
Accept: "text/event-stream",
},
body: JSON.stringify(openAiRequest),
@ -244,9 +246,7 @@ class ChatApi {
const response = await fetch(`${this.baseUrl}${API_ENDPOINTS.CHAT}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
headers: getAuthHeaders(),
body: JSON.stringify(requestBody),
});
@ -264,9 +264,7 @@ class ChatApi {
async stopChat(messageId?: string) {
await fetch(`${this.baseUrl}${API_ENDPOINTS.STOP}/${messageId}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
headers: getAuthHeaders(),
});
}
@ -326,8 +324,13 @@ class ChatApi {
const formData = new FormData();
formData.append("file", file);
// 获取认证 headers但不包含 Content-Type让浏览器为 FormData 自动设置)
const authHeaders = getAuthHeaders();
const { 'Content-Type': _, ...headersWithoutContentType } = authHeaders;
const response = await fetch(`${this.baseUrl}${API_ENDPOINTS.UPLOAD}`, {
method: "POST",
headers: headersWithoutContentType,
body: formData,
});

View File

@ -1,10 +1,10 @@
/**
* API
*
* API
* API
*/
import { authService } from './authService';
import { getAuthHeaders } from './request';
import type { Conversation, Message, MessageContent, ConversationSettings } from '@/types/chat';
// API 端点
@ -45,12 +45,7 @@ interface BackendMessage {
*
*/
function getHeaders(): Record<string, string> {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// 添加认证 header预留
const authHeader = authService.getAuthHeader();
return { ...headers, ...authHeader };
return getAuthHeaders();
}
/**

View File

@ -50,7 +50,14 @@ export async function apiRequest(
},
};
return fetch(url, config);
const response = await fetch(url, config);
// 401 认证失败提示
if (response.status === 401) {
window.$toast?.('认证失败,请重新登录', 'error');
}
return response;
}
/**

View File

@ -40,12 +40,18 @@ export const useAuthStore = defineStore('auth', () => {
return null;
}
const data: AuthResponse = await response.json();
if (data.success && data.data) {
window.$toast?.(`登录成功, 欢迎 ${data.data.nickname || data.data.username}`, 'success');
return data.data;
}else{
window.$toast?.('[Auth] Token 验证失败:Token无效');
}
return null;
} catch (error) {
console.error('[Auth] Token 验证失败:', error);
return null;
}
@ -73,7 +79,6 @@ export const useAuthStore = defineStore('auth', () => {
const userInfo = await checkToken(tokenValue);
if (userInfo) {
window.$toast?.(`登录成功, 欢迎 ${userInfo.nickname || userInfo.username}`, 'success');
token.value = tokenValue;
user.value = userInfo;

View File

@ -1 +1 @@
{"root":["./src/main.ts","./src/components/icons/index.ts","./src/composables/useKeyboard.ts","./src/services/api.ts","./src/services/authService.ts","./src/services/conversationApi.ts","./src/stores/chat.ts","./src/stores/settings.ts","./src/types/chat.ts","./src/utils/helpers.ts","./src/utils/migrateData.ts","./src/App.vue","./src/components/chat/ChatHeader.vue","./src/components/chat/ChatMain.vue","./src/components/chat/MessageList.vue","./src/components/chat/WelcomeScreen.vue","./src/components/input/AttachmentPreview.vue","./src/components/input/ChatInput.vue","./src/components/message/CodeBlock.vue","./src/components/message/MessageActions.vue","./src/components/message/MessageBubble.vue","./src/components/message/components/EChartsContainerNode.vue","./src/components/message/components/Loading.vue","./src/components/message/components/ThinkingNode.vue","./src/components/modals/ConversationSettingsModal.vue","./src/components/modals/SearchModal.vue","./src/components/modals/SettingsModal.vue","./src/components/modals/ShortcutsModal.vue","./src/components/sidebar/ChatSidebar.vue","./src/components/sidebar/ConversationItem.vue","./src/components/ui/FormSelect.vue","./src/components/ui/FormSlider.vue","./src/components/ui/FormSwitch.vue"],"errors":true,"version":"5.9.3"}
{"root":["./src/main.ts","./src/components/icons/index.ts","./src/composables/useKeyboard.ts","./src/services/api.ts","./src/services/authService.ts","./src/services/conversationApi.ts","./src/services/request.ts","./src/stores/auth.ts","./src/stores/chat.ts","./src/stores/settings.ts","./src/types/chat.ts","./src/utils/helpers.ts","./src/utils/migrateData.ts","./src/App.vue","./src/components/chat/ChatHeader.vue","./src/components/chat/ChatMain.vue","./src/components/chat/MessageList.vue","./src/components/chat/WelcomeScreen.vue","./src/components/input/AttachmentPreview.vue","./src/components/input/ChatInput.vue","./src/components/message/CodeBlock.vue","./src/components/message/MessageActions.vue","./src/components/message/MessageBubble.vue","./src/components/message/components/EChartsContainerNode.vue","./src/components/message/components/Loading.vue","./src/components/message/components/ThinkingNode.vue","./src/components/modals/ConversationSettingsModal.vue","./src/components/modals/SearchModal.vue","./src/components/modals/SettingsModal.vue","./src/components/modals/ShortcutsModal.vue","./src/components/sidebar/ChatSidebar.vue","./src/components/sidebar/ConversationItem.vue","./src/components/ui/FormSelect.vue","./src/components/ui/FormSlider.vue","./src/components/ui/FormSwitch.vue"],"errors":true,"version":"5.9.3"}