Add brain and chat workspace views
Expand the frontend with brain, graph, and chat workspace updates so the new backend orchestration and memory features have matching screens. These changes also wire the new APIs into routing and add focused view and routing tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,9 +2,14 @@ import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import api from '@/api'
|
||||
|
||||
let unauthorizedListenerRegistered = false
|
||||
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
const token = ref<string | null>(localStorage.getItem('access_token'))
|
||||
const user = ref<{ id: string; email: string; full_name?: string } | null>(null)
|
||||
const isAuthReady = ref(false)
|
||||
const isFetchingUser = ref(false)
|
||||
let authReadyPromise: Promise<void> | null = null
|
||||
|
||||
const isAuthenticated = computed(() => !!token.value)
|
||||
|
||||
@@ -17,28 +22,63 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
})
|
||||
token.value = response.data.access_token
|
||||
localStorage.setItem('access_token', response.data.access_token)
|
||||
user.value = null
|
||||
isAuthReady.value = false
|
||||
await fetchUser()
|
||||
}
|
||||
|
||||
async function fetchUser() {
|
||||
if (!token.value) return
|
||||
if (!token.value) {
|
||||
user.value = null
|
||||
isAuthReady.value = true
|
||||
return
|
||||
}
|
||||
|
||||
isFetchingUser.value = true
|
||||
try {
|
||||
const response = await api.get('/api/auth/me')
|
||||
user.value = response.data
|
||||
} catch {
|
||||
logout()
|
||||
} catch (error: any) {
|
||||
const status = error?.response?.status
|
||||
if (status === 401 || status === 403) {
|
||||
logout()
|
||||
} else {
|
||||
console.error('获取当前用户失败:', error)
|
||||
}
|
||||
} finally {
|
||||
isFetchingUser.value = false
|
||||
isAuthReady.value = true
|
||||
}
|
||||
}
|
||||
|
||||
function logout() {
|
||||
token.value = null
|
||||
user.value = null
|
||||
isFetchingUser.value = false
|
||||
isAuthReady.value = true
|
||||
localStorage.removeItem('access_token')
|
||||
}
|
||||
|
||||
if (token.value) {
|
||||
fetchUser()
|
||||
async function ensureAuthReady() {
|
||||
if (isAuthReady.value) return
|
||||
if (!authReadyPromise) {
|
||||
authReadyPromise = fetchUser().finally(() => {
|
||||
authReadyPromise = null
|
||||
})
|
||||
}
|
||||
await authReadyPromise
|
||||
}
|
||||
|
||||
return { token, user, isAuthenticated, login, logout, fetchUser }
|
||||
if (typeof window !== 'undefined' && !unauthorizedListenerRegistered) {
|
||||
window.addEventListener('jarvis:auth-unauthorized', logout)
|
||||
unauthorizedListenerRegistered = true
|
||||
}
|
||||
|
||||
if (token.value) {
|
||||
void ensureAuthReady()
|
||||
} else {
|
||||
isAuthReady.value = true
|
||||
}
|
||||
|
||||
return { token, user, isAuthenticated, isAuthReady, isFetchingUser, login, logout, fetchUser, ensureAuthReady }
|
||||
})
|
||||
|
||||
@@ -12,7 +12,7 @@ export const useConversationStore = defineStore('conversation', () => {
|
||||
conversations.value = data
|
||||
}
|
||||
|
||||
function setCurrentConversation(id: string) {
|
||||
function setCurrentConversation(id: string | null) {
|
||||
currentConversationId.value = id
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ export const useConversationStore = defineStore('conversation', () => {
|
||||
messages.value.push(msg)
|
||||
}
|
||||
|
||||
function removeMessage(id: string) {
|
||||
messages.value = messages.value.filter((msg) => msg.id !== id)
|
||||
}
|
||||
|
||||
function setMessages(data: Message[]) {
|
||||
messages.value = data
|
||||
}
|
||||
@@ -40,6 +44,7 @@ export const useConversationStore = defineStore('conversation', () => {
|
||||
setConversations,
|
||||
setCurrentConversation,
|
||||
addMessage,
|
||||
removeMessage,
|
||||
setMessages,
|
||||
addConversation,
|
||||
removeConversation,
|
||||
|
||||
Reference in New Issue
Block a user