- Created useSearchSession composable for session management - Added 7 API endpoints in api/index.ts - Updated SearchView.vue to use sessions instead of history - Session sidebar with create, rename, delete functionality - Auto-save messages to current session after each search - Auto-create default session on first load - Updated CSS for session active state and new session button
220 lines
6.2 KiB
TypeScript
220 lines
6.2 KiB
TypeScript
import { ref } from 'vue'
|
|
import { getApiBase } from '@/api/config'
|
|
|
|
export interface SearchSession {
|
|
id: string
|
|
title: string
|
|
mode: 'keyword' | 'visual' | 'people' | 'agent'
|
|
message_count: number
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface SearchMessage {
|
|
id: string
|
|
session_id: string
|
|
role: 'user' | 'assistant'
|
|
content: string
|
|
results: string
|
|
mode: string
|
|
created_at: string
|
|
}
|
|
|
|
export function useSearchSession() {
|
|
const sessions = ref<SearchSession[]>([])
|
|
const currentSession = ref<SearchSession | null>(null)
|
|
const messages = ref<SearchMessage[]>([])
|
|
const loading = ref(false)
|
|
const error = ref<string | null>(null)
|
|
|
|
function getAuthHeaders(): Record<string, string> {
|
|
const stored = localStorage.getItem('mb_admin_token')
|
|
if (stored) {
|
|
try {
|
|
const data = JSON.parse(stored)
|
|
if (new Date(data.expires_at) > new Date()) {
|
|
return { 'Authorization': `Bearer ${data.token}` }
|
|
}
|
|
} catch {}
|
|
}
|
|
return {}
|
|
}
|
|
|
|
async function loadSessions() {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const base = getApiBase()
|
|
const resp = await fetch(`${base}/api/v2/search-sessions`, {
|
|
headers: getAuthHeaders()
|
|
})
|
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
|
const data = await resp.json()
|
|
sessions.value = data.sessions || []
|
|
} catch (e: any) {
|
|
error.value = e.message || 'Failed to load sessions'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function createSession(title?: string, mode?: string) {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const base = getApiBase()
|
|
const resp = await fetch(`${base}/api/v2/search-sessions`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
|
|
body: JSON.stringify({ title: title || '未命名搜尋', mode: mode || 'keyword' })
|
|
})
|
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
|
const data = await resp.json()
|
|
await loadSessions()
|
|
return data.session
|
|
} catch (e: any) {
|
|
error.value = e.message || 'Failed to create session'
|
|
return null
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function renameSession(id: string, title: string) {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const base = getApiBase()
|
|
const resp = await fetch(`${base}/api/v2/search-sessions/${id}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
|
|
body: JSON.stringify({ title })
|
|
})
|
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
|
await loadSessions()
|
|
if (currentSession.value?.id === id) {
|
|
currentSession.value.title = title
|
|
}
|
|
} catch (e: any) {
|
|
error.value = e.message || 'Failed to rename session'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function deleteSession(id: string) {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const base = getApiBase()
|
|
const resp = await fetch(`${base}/api/v2/search-sessions/${id}`, {
|
|
method: 'DELETE',
|
|
headers: getAuthHeaders()
|
|
})
|
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
|
if (currentSession.value?.id === id) {
|
|
currentSession.value = null
|
|
messages.value = []
|
|
}
|
|
await loadSessions()
|
|
} catch (e: any) {
|
|
error.value = e.message || 'Failed to delete session'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function loadMessages(sessionId: string) {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const base = getApiBase()
|
|
const resp = await fetch(`${base}/api/v2/search-sessions/${sessionId}/messages`, {
|
|
headers: getAuthHeaders()
|
|
})
|
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
|
const data = await resp.json()
|
|
messages.value = data.messages || []
|
|
} catch (e: any) {
|
|
error.value = e.message || 'Failed to load messages'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function saveMessage(sessionId: string, message: { role: string; content: string; mode?: string; results?: any }) {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const base = getApiBase()
|
|
const resp = await fetch(`${base}/api/v2/search-sessions/${sessionId}/messages`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
|
|
body: JSON.stringify({
|
|
role: message.role,
|
|
content: message.content,
|
|
mode: message.mode || 'keyword',
|
|
results: message.results ? JSON.stringify(message.results) : ''
|
|
})
|
|
})
|
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
|
const data = await resp.json()
|
|
await loadMessages(sessionId)
|
|
await loadSessions()
|
|
return data.message
|
|
} catch (e: any) {
|
|
error.value = e.message || 'Failed to save message'
|
|
return null
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function updateMessage(sessionId: string, msgId: string, update: { role?: string; content?: string; results?: any }) {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const base = getApiBase()
|
|
const resp = await fetch(`${base}/api/v2/search-sessions/${sessionId}/messages/${msgId}`, {
|
|
method: 'PATCH',
|
|
headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
|
|
body: JSON.stringify({
|
|
...update,
|
|
results: update.results ? JSON.stringify(update.results) : undefined
|
|
})
|
|
})
|
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
|
await loadMessages(sessionId)
|
|
} catch (e: any) {
|
|
error.value = e.message || 'Failed to update message'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function setCurrentSession(session: SearchSession | null) {
|
|
currentSession.value = session
|
|
if (session) {
|
|
loadMessages(session.id)
|
|
} else {
|
|
messages.value = []
|
|
}
|
|
}
|
|
|
|
return {
|
|
sessions,
|
|
currentSession,
|
|
messages,
|
|
loading,
|
|
error,
|
|
loadSessions,
|
|
createSession,
|
|
renameSession,
|
|
deleteSession,
|
|
loadMessages,
|
|
saveMessage,
|
|
updateMessage,
|
|
setCurrentSession
|
|
}
|
|
}
|