重命名前端项目目录:web-flowith -> web
- 将前端项目目录从 web-flowith 重命名为 web,使目录结构更简洁 - 保持所有前端代码和配置文件不变 - 统一项目目录命名规范
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import type { ThemeConfig } from '@/types'
|
||||
|
||||
export const useAppStore = defineStore('app', () => {
|
||||
// 应用状态
|
||||
const loading = ref(false)
|
||||
const mobileMenuVisible = ref(false)
|
||||
const theme = ref<ThemeConfig>({
|
||||
primaryColor: '#4A90E2',
|
||||
secondaryColor: '#F5A623',
|
||||
backgroundColor: '#F7F8FA',
|
||||
textColor: '#333333',
|
||||
borderRadius: '8px'
|
||||
})
|
||||
|
||||
// 设备信息
|
||||
const isMobile = ref(false)
|
||||
const screenWidth = ref(window.innerWidth)
|
||||
|
||||
// 方法
|
||||
const setLoading = (value: boolean) => {
|
||||
loading.value = value
|
||||
}
|
||||
|
||||
const toggleMobileMenu = () => {
|
||||
mobileMenuVisible.value = !mobileMenuVisible.value
|
||||
}
|
||||
|
||||
const closeMobileMenu = () => {
|
||||
mobileMenuVisible.value = false
|
||||
}
|
||||
|
||||
const updateScreenWidth = () => {
|
||||
screenWidth.value = window.innerWidth
|
||||
isMobile.value = window.innerWidth < 768
|
||||
}
|
||||
|
||||
const setTheme = (newTheme: Partial<ThemeConfig>) => {
|
||||
theme.value = { ...theme.value, ...newTheme }
|
||||
}
|
||||
|
||||
// 初始化
|
||||
const init = () => {
|
||||
updateScreenWidth()
|
||||
window.addEventListener('resize', updateScreenWidth)
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
loading,
|
||||
mobileMenuVisible,
|
||||
theme,
|
||||
isMobile,
|
||||
screenWidth,
|
||||
|
||||
// 方法
|
||||
setLoading,
|
||||
toggleMobileMenu,
|
||||
closeMobileMenu,
|
||||
updateScreenWidth,
|
||||
setTheme,
|
||||
init
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,353 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, watch } from 'vue'
|
||||
import type { ChatMessage, ChatSession } from '@/types'
|
||||
import webSocketService, { type WebSocketMessage, type ConnectionStatus } from '@/services/websocket'
|
||||
import { useUserStore } from './user'
|
||||
import { chatApi } from '@/services/chat'
|
||||
|
||||
export const useChatStore = defineStore('chat', () => {
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 聊天状态
|
||||
const currentSession = ref<ChatSession | null>(null)
|
||||
const messages = ref<ChatMessage[]>([])
|
||||
const sessions = ref<ChatSession[]>([])
|
||||
const isTyping = ref(false)
|
||||
const isConnected = ref(false)
|
||||
const connectionStatus = ref<ConnectionStatus>('DISCONNECTED')
|
||||
const wsConnected = ref(false)
|
||||
|
||||
// 方法
|
||||
const addMessage = (message: Omit<ChatMessage, 'id' | 'timestamp'>) => {
|
||||
const newMessage: ChatMessage = {
|
||||
...message,
|
||||
id: Date.now().toString(),
|
||||
timestamp: new Date().toISOString(),
|
||||
status: message.type === 'user' ? 'sending' : 'sent'
|
||||
}
|
||||
messages.value.push(newMessage)
|
||||
return newMessage
|
||||
}
|
||||
|
||||
// 更新消息状态
|
||||
const updateMessageStatus = (messageId: string, status: ChatMessage['status'], error?: string) => {
|
||||
const message = messages.value.find(m => m.id === messageId)
|
||||
if (message) {
|
||||
message.status = status
|
||||
if (error) {
|
||||
message.error = error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息:WebSocket推送+数据库保存
|
||||
const sendMessage = async (content: string) => {
|
||||
if (!wsConnected.value) {
|
||||
console.error('WebSocket未连接,无法发送消息')
|
||||
addMessage({
|
||||
content: '连接已断开,请刷新页面重试。',
|
||||
type: 'ai',
|
||||
sessionId: currentSession.value?.id
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 添加用户消息
|
||||
const userMessage = addMessage({
|
||||
content,
|
||||
type: 'user',
|
||||
sessionId: currentSession.value?.id
|
||||
})
|
||||
|
||||
try {
|
||||
// WebSocket推送
|
||||
webSocketService.sendChatMessage(content, currentSession.value?.id)
|
||||
|
||||
// 更新消息状态为已发送
|
||||
updateMessageStatus(userMessage.id, 'sent')
|
||||
|
||||
// 数据库保存
|
||||
if (currentSession.value?.id && userStore.user?.id) {
|
||||
await chatApi.createMessage({
|
||||
conversationId: currentSession.value.id,
|
||||
userId: userStore.user.id,
|
||||
content,
|
||||
contentType: 'TEXT',
|
||||
senderType: 'USER',
|
||||
senderId: userStore.user.id
|
||||
})
|
||||
|
||||
// 更新消息状态为已送达
|
||||
updateMessageStatus(userMessage.id, 'delivered')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('消息发送或保存失败:', error)
|
||||
|
||||
// 更新消息状态为失败
|
||||
updateMessageStatus(userMessage.id, 'failed', '发送失败')
|
||||
|
||||
addMessage({
|
||||
content: '抱歉,消息发送失败,请稍后重试。',
|
||||
type: 'ai',
|
||||
sessionId: currentSession.value?.id
|
||||
})
|
||||
}
|
||||
return userMessage
|
||||
}
|
||||
|
||||
// 创建会话:同步后端
|
||||
const createSession = async (title?: string) => {
|
||||
let newSession: ChatSession
|
||||
if (userStore.user?.id) {
|
||||
newSession = await chatApi.createSession(userStore.user.id, title || `对话${sessions.value.length + 1}`)
|
||||
} else {
|
||||
newSession = {
|
||||
id: Date.now().toString(),
|
||||
title: title || `对话${sessions.value.length + 1}`,
|
||||
createTime: new Date().toISOString(),
|
||||
updateTime: new Date().toISOString(),
|
||||
messageCount: 0
|
||||
}
|
||||
}
|
||||
sessions.value.unshift(newSession)
|
||||
currentSession.value = newSession
|
||||
messages.value = []
|
||||
|
||||
// 如果WebSocket已连接,设置新的会话ID
|
||||
if (wsConnected.value) {
|
||||
webSocketService.setConversationId(newSession.id)
|
||||
}
|
||||
|
||||
return newSession
|
||||
}
|
||||
|
||||
// 切换会话:加载消息
|
||||
const switchSession = async (sessionId: string) => {
|
||||
const session = sessions.value.find(s => s.id === sessionId)
|
||||
if (session) {
|
||||
currentSession.value = session
|
||||
await loadSessionMessages(sessionId)
|
||||
|
||||
// 如果WebSocket已连接,更新会话ID
|
||||
if (wsConnected.value) {
|
||||
webSocketService.setConversationId(sessionId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载会话消息:从后端获取
|
||||
const loadSessionMessages = async (sessionId: string) => {
|
||||
try {
|
||||
const msgs = await chatApi.getAllSessionMessages(sessionId)
|
||||
messages.value = msgs
|
||||
} catch (error) {
|
||||
console.error('Failed to load session messages:', error)
|
||||
messages.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 删除会话:同步后端
|
||||
const deleteSession = async (sessionId: string) => {
|
||||
try {
|
||||
await chatApi.deleteSession(sessionId)
|
||||
const index = sessions.value.findIndex(s => s.id === sessionId)
|
||||
if (index > -1) {
|
||||
sessions.value.splice(index, 1)
|
||||
if (currentSession.value?.id === sessionId) {
|
||||
currentSession.value = sessions.value[0] || null
|
||||
if (currentSession.value) {
|
||||
await loadSessionMessages(currentSession.value.id)
|
||||
} else {
|
||||
messages.value = []
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除会话失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const clearMessages = () => {
|
||||
messages.value = []
|
||||
}
|
||||
|
||||
const searchMessages = (keyword: string) => {
|
||||
return messages.value.filter(message =>
|
||||
message.content.toLowerCase().includes(keyword.toLowerCase())
|
||||
)
|
||||
}
|
||||
|
||||
// 分割AI回复为多条消息
|
||||
const splitAiReply = (content: string): string[] => {
|
||||
// 先按 \n\n 分割,再按 \n 分割
|
||||
const segments = content.split(/\n\n|\n/).filter(segment => segment.trim().length > 0)
|
||||
return segments
|
||||
}
|
||||
|
||||
// 添加AI回复消息(支持分段显示)
|
||||
const addAiReplyMessages = (content: string, delay: number = 1000) => {
|
||||
const segments = splitAiReply(content)
|
||||
|
||||
segments.forEach((segment, index) => {
|
||||
setTimeout(() => {
|
||||
addMessage({
|
||||
content: segment.trim(),
|
||||
type: 'ai',
|
||||
sessionId: currentSession.value?.id
|
||||
})
|
||||
|
||||
// 最后一条消息后停止输入状态
|
||||
if (index === segments.length - 1) {
|
||||
isTyping.value = false
|
||||
}
|
||||
}, index * delay)
|
||||
})
|
||||
}
|
||||
|
||||
// WebSocket消息处理
|
||||
const handleWebSocketMessage = (wsMessage: WebSocketMessage) => {
|
||||
console.log('处理WebSocket消息:', wsMessage)
|
||||
|
||||
switch (wsMessage.type) {
|
||||
case 'TEXT':
|
||||
if (wsMessage.senderType === 'AI') {
|
||||
// AI回复消息 - 支持分段显示
|
||||
addAiReplyMessages(wsMessage.content)
|
||||
}
|
||||
break
|
||||
|
||||
case 'AI_THINKING':
|
||||
// AI正在思考
|
||||
isTyping.value = true
|
||||
break
|
||||
|
||||
case 'CONNECTION':
|
||||
// 连接状态消息
|
||||
console.log('WebSocket连接状态:', wsMessage.content)
|
||||
break
|
||||
|
||||
case 'ERROR':
|
||||
// 错误消息
|
||||
addMessage({
|
||||
content: wsMessage.content,
|
||||
type: 'ai',
|
||||
sessionId: currentSession.value?.id
|
||||
})
|
||||
isTyping.value = false
|
||||
break
|
||||
|
||||
case 'SYSTEM':
|
||||
// 系统消息
|
||||
addMessage({
|
||||
content: wsMessage.content,
|
||||
type: 'ai',
|
||||
sessionId: currentSession.value?.id
|
||||
})
|
||||
break
|
||||
|
||||
default:
|
||||
console.log('未处理的消息类型:', wsMessage.type)
|
||||
}
|
||||
}
|
||||
|
||||
// WebSocket连接管理
|
||||
const connectWebSocket = async () => {
|
||||
try {
|
||||
// 优先使用userInfo中的用户ID,如果没有则使用user中的ID
|
||||
const userId = userStore.userInfo?.id || userStore.user?.id || undefined
|
||||
|
||||
await webSocketService.connect(userId, {
|
||||
onMessage: handleWebSocketMessage,
|
||||
onConnect: () => {
|
||||
console.log('WebSocket连接成功')
|
||||
wsConnected.value = true
|
||||
isConnected.value = true
|
||||
|
||||
// 设置会话ID
|
||||
if (currentSession.value?.id) {
|
||||
webSocketService.setConversationId(currentSession.value.id)
|
||||
}
|
||||
},
|
||||
onDisconnect: () => {
|
||||
console.log('WebSocket连接断开')
|
||||
wsConnected.value = false
|
||||
isConnected.value = false
|
||||
isTyping.value = false
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('WebSocket错误:', error)
|
||||
wsConnected.value = false
|
||||
isConnected.value = false
|
||||
isTyping.value = false
|
||||
|
||||
// 显示用户友好的错误信息
|
||||
if (error.userMessage) {
|
||||
addMessage({
|
||||
content: error.userMessage,
|
||||
type: 'ai',
|
||||
sessionId: currentSession.value?.id
|
||||
})
|
||||
}
|
||||
},
|
||||
onStatusChange: (status) => {
|
||||
connectionStatus.value = status
|
||||
isConnected.value = status === 'CONNECTED'
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('WebSocket连接失败:', error)
|
||||
wsConnected.value = false
|
||||
isConnected.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const disconnectWebSocket = () => {
|
||||
webSocketService.disconnect()
|
||||
wsConnected.value = false
|
||||
isConnected.value = false
|
||||
isTyping.value = false
|
||||
}
|
||||
|
||||
// 初始化
|
||||
const initChat = async () => {
|
||||
// 如果没有会话,创建一个默认会话
|
||||
if (sessions.value.length === 0) {
|
||||
await createSession('与开开的对话')
|
||||
}
|
||||
|
||||
// 连接WebSocket
|
||||
await connectWebSocket()
|
||||
}
|
||||
|
||||
// 监听会话变化,更新WebSocket会话ID
|
||||
watch(currentSession, (newSession) => {
|
||||
if (newSession?.id && wsConnected.value) {
|
||||
webSocketService.setConversationId(newSession.id)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
// 状态
|
||||
currentSession,
|
||||
messages,
|
||||
sessions,
|
||||
isTyping,
|
||||
isConnected,
|
||||
connectionStatus,
|
||||
wsConnected,
|
||||
|
||||
// 方法
|
||||
addMessage,
|
||||
sendMessage,
|
||||
createSession,
|
||||
switchSession,
|
||||
loadSessionMessages,
|
||||
deleteSession,
|
||||
clearMessages,
|
||||
searchMessages,
|
||||
initChat,
|
||||
connectWebSocket,
|
||||
disconnectWebSocket,
|
||||
handleWebSocketMessage
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,157 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import type { DiaryEntry } from '@/types'
|
||||
|
||||
export const useDiaryStore = defineStore('diary', () => {
|
||||
// 日记状态
|
||||
const entries = ref<DiaryEntry[]>([])
|
||||
const currentEntry = ref<DiaryEntry | null>(null)
|
||||
const isLoading = ref(false)
|
||||
|
||||
// 方法
|
||||
const addEntry = async (content: string, mood?: string, tags?: string[]) => {
|
||||
isLoading.value = true
|
||||
|
||||
try {
|
||||
const newEntry: DiaryEntry = {
|
||||
id: Date.now().toString(),
|
||||
content,
|
||||
mood,
|
||||
tags: tags || [],
|
||||
createTime: new Date().toISOString(),
|
||||
updateTime: new Date().toISOString()
|
||||
}
|
||||
|
||||
// TODO: 调用API保存日记
|
||||
// const response = await diaryApi.createEntry(newEntry)
|
||||
|
||||
// 模拟AI回复
|
||||
setTimeout(() => {
|
||||
newEntry.aiReply = generateAIReply(content, mood)
|
||||
entries.value.unshift(newEntry)
|
||||
isLoading.value = false
|
||||
}, 1000)
|
||||
|
||||
return newEntry
|
||||
} catch (error) {
|
||||
console.error('Failed to add diary entry:', error)
|
||||
isLoading.value = false
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const updateEntry = async (id: string, updates: Partial<DiaryEntry>) => {
|
||||
const index = entries.value.findIndex(entry => entry.id === id)
|
||||
if (index > -1) {
|
||||
entries.value[index] = {
|
||||
...entries.value[index],
|
||||
...updates,
|
||||
updateTime: new Date().toISOString()
|
||||
}
|
||||
|
||||
// TODO: 调用API更新日记
|
||||
// await diaryApi.updateEntry(id, updates)
|
||||
}
|
||||
}
|
||||
|
||||
const deleteEntry = async (id: string) => {
|
||||
const index = entries.value.findIndex(entry => entry.id === id)
|
||||
if (index > -1) {
|
||||
entries.value.splice(index, 1)
|
||||
|
||||
// TODO: 调用API删除日记
|
||||
// await diaryApi.deleteEntry(id)
|
||||
}
|
||||
}
|
||||
|
||||
const getEntry = (id: string) => {
|
||||
return entries.value.find(entry => entry.id === id)
|
||||
}
|
||||
|
||||
const searchEntries = (keyword: string) => {
|
||||
return entries.value.filter(entry =>
|
||||
entry.content.toLowerCase().includes(keyword.toLowerCase()) ||
|
||||
entry.tags?.some(tag => tag.toLowerCase().includes(keyword.toLowerCase()))
|
||||
)
|
||||
}
|
||||
|
||||
const getEntriesByMood = (mood: string) => {
|
||||
return entries.value.filter(entry => entry.mood === mood)
|
||||
}
|
||||
|
||||
const getEntriesByDateRange = (startDate: string, endDate: string) => {
|
||||
return entries.value.filter(entry => {
|
||||
const entryDate = new Date(entry.createTime).toISOString().split('T')[0]
|
||||
return entryDate >= startDate && entryDate <= endDate
|
||||
})
|
||||
}
|
||||
|
||||
const loadEntries = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
try {
|
||||
// TODO: 从API加载日记列表
|
||||
// const response = await diaryApi.getEntries()
|
||||
// entries.value = response.data
|
||||
|
||||
// 临时模拟数据
|
||||
entries.value = [
|
||||
{
|
||||
id: '1',
|
||||
content: '今天天气很好,心情也不错。和朋友一起去公园散步,看到了很多美丽的花朵。',
|
||||
mood: 'happy',
|
||||
tags: ['散步', '朋友', '公园'],
|
||||
createTime: new Date(Date.now() - 86400000).toISOString(),
|
||||
updateTime: new Date(Date.now() - 86400000).toISOString(),
|
||||
aiReply: '听起来你度过了美好的一天!和朋友一起在大自然中放松是很棒的体验。这样的时光能让我们感受到生活的美好。'
|
||||
}
|
||||
]
|
||||
|
||||
isLoading.value = false
|
||||
} catch (error) {
|
||||
console.error('Failed to load diary entries:', error)
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 生成AI回复的辅助函数
|
||||
const generateAIReply = (content: string, mood?: string) => {
|
||||
const replies = {
|
||||
happy: [
|
||||
'很高兴看到你心情愉快!继续保持这份美好的心情吧。',
|
||||
'你的快乐感染了我!希望这份喜悦能持续下去。',
|
||||
'看到你开心,我也很开心。愿你每天都有这样的好心情!'
|
||||
],
|
||||
sad: [
|
||||
'我能感受到你的难过。记住,这只是暂时的,一切都会好起来的。',
|
||||
'每个人都会有低落的时候,这很正常。我会陪伴你度过这段时光。',
|
||||
'虽然现在感到难过,但请相信明天会更好。我一直在这里支持你。'
|
||||
],
|
||||
neutral: [
|
||||
'感谢你分享今天的经历。每一天都是独特的,值得被记录。',
|
||||
'生活就是这样平凡而珍贵。感谢你让我了解你的日常。',
|
||||
'平静的日子也有它的美好。希望你能在平凡中发现小确幸。'
|
||||
]
|
||||
}
|
||||
|
||||
const moodReplies = replies[mood as keyof typeof replies] || replies.neutral
|
||||
return moodReplies[Math.floor(Math.random() * moodReplies.length)]
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
entries,
|
||||
currentEntry,
|
||||
isLoading,
|
||||
|
||||
// 方法
|
||||
addEntry,
|
||||
updateEntry,
|
||||
deleteEntry,
|
||||
getEntry,
|
||||
searchEntries,
|
||||
getEntriesByMood,
|
||||
getEntriesByDateRange,
|
||||
loadEntries
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
const pinia = createPinia()
|
||||
|
||||
export default pinia
|
||||
|
||||
// 导出所有store
|
||||
export { useUserStore } from './user'
|
||||
export { useChatStore } from './chat'
|
||||
export { useDiaryStore } from './diary'
|
||||
export { useAppStore } from './app'
|
||||
@@ -0,0 +1,157 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { authService, authUtils } from '@/services/auth'
|
||||
import type { User } from '@/types'
|
||||
import type { UserInfo, LoginRequest } from '@/types/auth'
|
||||
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
// 用户状态
|
||||
const user = ref<User | null>(null)
|
||||
const userInfo = ref<UserInfo | null>(null)
|
||||
const token = ref<string>('')
|
||||
const isLoading = ref(false)
|
||||
const isLoggedIn = computed(() => !!token.value && (!!user.value || !!userInfo.value))
|
||||
|
||||
// 方法
|
||||
const setUser = (userData: User) => {
|
||||
user.value = userData
|
||||
}
|
||||
|
||||
const setToken = (tokenValue: string) => {
|
||||
token.value = tokenValue
|
||||
// 存储到localStorage
|
||||
if (tokenValue) {
|
||||
localStorage.setItem('token', tokenValue)
|
||||
} else {
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
}
|
||||
|
||||
const setUserInfo = (userInfoData: UserInfo | null) => {
|
||||
userInfo.value = userInfoData
|
||||
// 存储到localStorage
|
||||
if (userInfoData) {
|
||||
localStorage.setItem('userInfo', JSON.stringify(userInfoData))
|
||||
} else {
|
||||
localStorage.removeItem('userInfo')
|
||||
}
|
||||
}
|
||||
|
||||
// 新的登录方法,支持认证服务
|
||||
const loginWithAuth = async (loginData: LoginRequest) => {
|
||||
isLoading.value = true
|
||||
try {
|
||||
const data = await authService.login(loginData)
|
||||
setToken(data.accessToken)
|
||||
setUserInfo(data.userInfo)
|
||||
return data
|
||||
} catch (error: any) {
|
||||
throw error
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const login = async (credentials: { username: string; password: string }) => {
|
||||
try {
|
||||
// TODO: 调用登录API
|
||||
// const response = await authApi.login(credentials)
|
||||
// setToken(response.data.token)
|
||||
// setUser(response.data.user)
|
||||
|
||||
// 临时模拟登录
|
||||
setToken('mock-token')
|
||||
setUser({
|
||||
id: '1',
|
||||
username: credentials.username,
|
||||
email: 'user@example.com',
|
||||
nickname: '用户',
|
||||
createTime: new Date().toISOString(),
|
||||
updateTime: new Date().toISOString()
|
||||
})
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('Login failed:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const logout = async () => {
|
||||
try {
|
||||
await authService.logout()
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error)
|
||||
} finally {
|
||||
// 清除状态和本地存储
|
||||
user.value = null
|
||||
userInfo.value = null
|
||||
setToken('')
|
||||
authUtils.clearAuth()
|
||||
}
|
||||
}
|
||||
|
||||
const updateProfile = (profileData: Partial<User>) => {
|
||||
if (user.value) {
|
||||
user.value = { ...user.value, ...profileData }
|
||||
// TODO: 调用更新API
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化用户状态
|
||||
const initUser = () => {
|
||||
const savedToken = authUtils.getToken()
|
||||
const savedUserInfo = authUtils.getUserInfo()
|
||||
|
||||
console.log('初始化用户状态:', { savedToken: !!savedToken, savedUserInfo })
|
||||
|
||||
if (savedToken) {
|
||||
setToken(savedToken)
|
||||
}
|
||||
|
||||
if (savedUserInfo) {
|
||||
setUserInfo(savedUserInfo)
|
||||
}
|
||||
|
||||
console.log('用户状态初始化完成:', {
|
||||
token: !!token.value,
|
||||
userInfo: userInfo.value,
|
||||
isLoggedIn: isLoggedIn.value
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新用户信息
|
||||
const refreshUserInfo = async () => {
|
||||
if (!token.value) return
|
||||
|
||||
try {
|
||||
const response = await authService.getUserInfo()
|
||||
if (response.success) {
|
||||
userInfo.value = response.data
|
||||
authUtils.setUserInfo(response.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Refresh user info error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
user,
|
||||
userInfo,
|
||||
token,
|
||||
isLoading,
|
||||
isLoggedIn,
|
||||
|
||||
// 方法
|
||||
setUser,
|
||||
setToken,
|
||||
setUserInfo,
|
||||
login,
|
||||
loginWithAuth,
|
||||
logout,
|
||||
updateProfile,
|
||||
initUser,
|
||||
refreshUserInfo
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user