首个可运行的版本

This commit is contained in:
2026-06-12 23:14:12 +08:00
commit b3d90c65f8
86 changed files with 4808 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { authApi } from '@/api/auth'
export const useAuthStore = defineStore('auth', () => {
const user = ref<any>(null)
const accessToken = ref(localStorage.getItem('access_token') || '')
const isAuthenticated = computed(() => !!accessToken.value && !!user.value)
async function login(username: string, password: string) {
const { data } = await authApi.login(username, password)
accessToken.value = data.access_token
localStorage.setItem('access_token', data.access_token)
localStorage.setItem('refresh_token', data.refresh_token)
user.value = data.user
}
async function register(username: string, email: string, password: string) {
const { data } = await authApi.register(username, email, password)
accessToken.value = data.access_token
localStorage.setItem('access_token', data.access_token)
localStorage.setItem('refresh_token', data.refresh_token)
user.value = data.user
}
async function fetchProfile() {
try {
const { data } = await authApi.getProfile()
user.value = data
} catch {
logout()
}
}
function logout() {
user.value = null
accessToken.value = ''
localStorage.removeItem('access_token')
localStorage.removeItem('refresh_token')
}
return { user, accessToken, isAuthenticated, login, register, fetchProfile, logout }
})
+49
View File
@@ -0,0 +1,49 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { chatApi } from '@/api/chat'
export const useChatStore = defineStore('chat', () => {
const conversations = ref<any[]>([])
const currentMessages = ref<any[]>([])
const activeConversation = ref<string | null>(null)
const isLoading = ref(false)
async function fetchConversations() {
isLoading.value = true
try {
const { data } = await chatApi.getConversations()
conversations.value = data
} finally {
isLoading.value = false
}
}
async function fetchMessages(conversationId: string, before?: string) {
const { data } = await chatApi.getMessages(conversationId, before)
if (before) {
currentMessages.value = [...data.messages, ...currentMessages.value]
} else {
currentMessages.value = data.messages
}
activeConversation.value = conversationId
}
function addMessage(message: any) {
currentMessages.value.push(message)
// 更新会话列表中的最后消息
const conv = conversations.value.find((c) => c.id === message.conversation_id)
if (conv) {
conv.last_message_preview = message.content?.substring(0, 50)
conv.last_message_at = message.created_at
}
}
async function markAsRead(conversationId: string, messageId: string) {
await chatApi.markAsRead(conversationId, messageId)
}
return {
conversations, currentMessages, activeConversation, isLoading,
fetchConversations, fetchMessages, addMessage, markAsRead,
}
})
+36
View File
@@ -0,0 +1,36 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export type LayoutMode = 'list' | 'card' | 'waterfall'
export type ChatStyle = 'classic' | 'compact' | 'bubble'
export const useUiStore = defineStore('ui', () => {
const layoutMode = ref<LayoutMode>((localStorage.getItem('layoutMode') as LayoutMode) || 'list')
const chatStyle = ref<ChatStyle>((localStorage.getItem('chatStyle') as ChatStyle) || 'bubble')
const sidebarCollapsed = ref(false)
const isMobile = ref(window.innerWidth < 768)
function setLayoutMode(mode: LayoutMode) {
layoutMode.value = mode
localStorage.setItem('layoutMode', mode)
}
function setChatStyle(style: ChatStyle) {
chatStyle.value = style
localStorage.setItem('chatStyle', style)
}
function toggleSidebar() {
sidebarCollapsed.value = !sidebarCollapsed.value
}
// 监听窗口大小
window.addEventListener('resize', () => {
isMobile.value = window.innerWidth < 768
})
return {
layoutMode, chatStyle, sidebarCollapsed, isMobile,
setLayoutMode, setChatStyle, toggleSidebar,
}
})