feat: 阻止未登录用户使用任何功能
This commit is contained in:
parent
ec96a424c4
commit
3421d0db47
|
|
@ -52,6 +52,7 @@ import { ref, computed, watch, nextTick, onMounted } from "vue";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { useChatStore } from "@/stores/chat";
|
import { useChatStore } from "@/stores/chat";
|
||||||
import { useSettingsStore } from "@/stores/settings";
|
import { useSettingsStore } from "@/stores/settings";
|
||||||
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import ChatHeader from "./ChatHeader.vue";
|
import ChatHeader from "./ChatHeader.vue";
|
||||||
import MessageList from "./MessageList.vue";
|
import MessageList from "./MessageList.vue";
|
||||||
import ChatInput from "@/components/input/ChatInput.vue";
|
import ChatInput from "@/components/input/ChatInput.vue";
|
||||||
|
|
@ -65,6 +66,7 @@ defineEmits<{
|
||||||
|
|
||||||
const chatStore = useChatStore();
|
const chatStore = useChatStore();
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
const { currentConversation, isStreaming } = storeToRefs(chatStore);
|
const { currentConversation, isStreaming } = storeToRefs(chatStore);
|
||||||
const { settings, sidebarCollapsed } = storeToRefs(settingsStore);
|
const { settings, sidebarCollapsed } = storeToRefs(settingsStore);
|
||||||
|
|
@ -164,6 +166,12 @@ async function handleSend(
|
||||||
systemPrompt?: string;
|
systemPrompt?: string;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
// 检查认证状态
|
||||||
|
if (!authStore.isAuthenticated) {
|
||||||
|
window.$toast?.('请先登录', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log("handleSend", text, attachments, options);
|
console.log("handleSend", text, attachments, options);
|
||||||
// 检查是否还有正在上传的附件
|
// 检查是否还有正在上传的附件
|
||||||
const uploadingAttachments = attachments.filter((a) => a.uploading);
|
const uploadingAttachments = attachments.filter((a) => a.uploading);
|
||||||
|
|
@ -337,6 +345,12 @@ function handleStop() {
|
||||||
|
|
||||||
// 重试
|
// 重试
|
||||||
async function handleRetry(messageId: string) {
|
async function handleRetry(messageId: string) {
|
||||||
|
// 检查认证状态
|
||||||
|
if (!authStore.isAuthenticated) {
|
||||||
|
window.$toast?.('请先登录', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const message = messages.value.find((m: any) => m.id === messageId);
|
const message = messages.value.find((m: any) => m.id === messageId);
|
||||||
if (!message || message.role !== MessageRole.ASSISTANT) return;
|
if (!message || message.role !== MessageRole.ASSISTANT) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,7 @@ import AttachmentPreview from "./AttachmentPreview.vue";
|
||||||
import { generateId } from "@/utils/helpers";
|
import { generateId } from "@/utils/helpers";
|
||||||
import type { Attachment } from "@/types/chat";
|
import type { Attachment } from "@/types/chat";
|
||||||
import { chatApi } from "@/services/api";
|
import { chatApi } from "@/services/api";
|
||||||
|
import { useAuthStore } from "@/stores/auth";
|
||||||
|
|
||||||
interface AttachmentWithProgress extends Attachment {
|
interface AttachmentWithProgress extends Attachment {
|
||||||
uploading?: boolean;
|
uploading?: boolean;
|
||||||
|
|
@ -216,6 +217,8 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// 响应式状态
|
// 响应式状态
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
const inputText = ref("");
|
const inputText = ref("");
|
||||||
const attachments = ref<AttachmentWithProgress[]>([]);
|
const attachments = ref<AttachmentWithProgress[]>([]);
|
||||||
const isFocused = ref(false);
|
const isFocused = ref(false);
|
||||||
|
|
@ -350,6 +353,12 @@ async function addFileAsAttachment(
|
||||||
file: File,
|
file: File,
|
||||||
type: "image" | "file" | "video",
|
type: "image" | "file" | "video",
|
||||||
) {
|
) {
|
||||||
|
// 检查认证状态
|
||||||
|
if (!authStore.isAuthenticated) {
|
||||||
|
window.$toast?.('请先登录', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const id = generateId();
|
const id = generateId();
|
||||||
|
|
||||||
// 创建本地预览URL
|
// 创建本地预览URL
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
* Chat UI API 服务
|
* Chat UI API 服务
|
||||||
* 所有端点都是固定的,后端需要实现这些端点
|
* 所有端点都是固定的,后端需要实现这些端点
|
||||||
*/
|
*/
|
||||||
|
import { getAuthHeaders } from './request';
|
||||||
|
|
||||||
// API 端点定义(固定)
|
// API 端点定义(固定)
|
||||||
const API_ENDPOINTS = {
|
const API_ENDPOINTS = {
|
||||||
// 发送消息(流式)
|
// 发送消息(流式)
|
||||||
|
|
@ -153,7 +155,7 @@ class ChatApi {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
...getAuthHeaders(),
|
||||||
Accept: "text/event-stream",
|
Accept: "text/event-stream",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(openAiRequest),
|
body: JSON.stringify(openAiRequest),
|
||||||
|
|
@ -244,9 +246,7 @@ class ChatApi {
|
||||||
|
|
||||||
const response = await fetch(`${this.baseUrl}${API_ENDPOINTS.CHAT}`, {
|
const response = await fetch(`${this.baseUrl}${API_ENDPOINTS.CHAT}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: getAuthHeaders(),
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(requestBody),
|
body: JSON.stringify(requestBody),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -264,9 +264,7 @@ class ChatApi {
|
||||||
async stopChat(messageId?: string) {
|
async stopChat(messageId?: string) {
|
||||||
await fetch(`${this.baseUrl}${API_ENDPOINTS.STOP}/${messageId}`, {
|
await fetch(`${this.baseUrl}${API_ENDPOINTS.STOP}/${messageId}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: getAuthHeaders(),
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,8 +324,13 @@ class ChatApi {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file);
|
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}`, {
|
const response = await fetch(`${this.baseUrl}${API_ENDPOINTS.UPLOAD}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
headers: headersWithoutContentType,
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
/**
|
/**
|
||||||
* 对话 API 服务层
|
* 对话 API 服务层
|
||||||
*
|
*
|
||||||
* 封装所有对话相关的后端 API 调用,支持认证预留
|
* 封装所有对话相关的后端 API 调用
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { authService } from './authService';
|
import { getAuthHeaders } from './request';
|
||||||
import type { Conversation, Message, MessageContent, ConversationSettings } from '@/types/chat';
|
import type { Conversation, Message, MessageContent, ConversationSettings } from '@/types/chat';
|
||||||
|
|
||||||
// API 端点
|
// API 端点
|
||||||
|
|
@ -45,12 +45,7 @@ interface BackendMessage {
|
||||||
* 获取请求头(包含认证信息)
|
* 获取请求头(包含认证信息)
|
||||||
*/
|
*/
|
||||||
function getHeaders(): Record<string, string> {
|
function getHeaders(): Record<string, string> {
|
||||||
const headers: Record<string, string> = {
|
return getAuthHeaders();
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
// 添加认证 header(预留)
|
|
||||||
const authHeader = authService.getAuthHeader();
|
|
||||||
return { ...headers, ...authHeader };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,17 @@ export const useAuthStore = defineStore('auth', () => {
|
||||||
}
|
}
|
||||||
const data: AuthResponse = await response.json();
|
const data: AuthResponse = await response.json();
|
||||||
|
|
||||||
|
|
||||||
if (data.success && data.data) {
|
if (data.success && data.data) {
|
||||||
|
window.$toast?.(`登录成功, 欢迎 ${data.data.nickname || data.data.username}`, 'success');
|
||||||
|
|
||||||
return data.data;
|
return data.data;
|
||||||
|
}else{
|
||||||
|
window.$toast?.('[Auth] Token 验证失败:Token无效');
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
console.error('[Auth] Token 验证失败:', error);
|
console.error('[Auth] Token 验证失败:', error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +79,6 @@ export const useAuthStore = defineStore('auth', () => {
|
||||||
const userInfo = await checkToken(tokenValue);
|
const userInfo = await checkToken(tokenValue);
|
||||||
|
|
||||||
if (userInfo) {
|
if (userInfo) {
|
||||||
window.$toast?.(`登录成功, 欢迎 ${userInfo.nickname || userInfo.username}`, 'success');
|
|
||||||
|
|
||||||
token.value = tokenValue;
|
token.value = tokenValue;
|
||||||
user.value = userInfo;
|
user.value = userInfo;
|
||||||
|
|
|
||||||
|
|
@ -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"}
|
||||||
Loading…
Reference in New Issue