2026-03-18 13:53:36 +08:00
|
|
|
import { api } from '@/utils/request'
|
|
|
|
|
|
|
|
|
|
export interface UserInfo {
|
|
|
|
|
id: number
|
|
|
|
|
username: string
|
|
|
|
|
email: string
|
|
|
|
|
role: string
|
|
|
|
|
status: number
|
2026-03-18 18:04:41 +08:00
|
|
|
ext?: Record<string, unknown> | null
|
2026-03-18 13:53:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const useUserStore = defineStore('user', () => {
|
|
|
|
|
const token = ref<string | null>(localStorage.getItem('access_token'))
|
|
|
|
|
const refreshToken = ref<string | null>(localStorage.getItem('refresh_token'))
|
|
|
|
|
const user = ref<UserInfo | null>(null)
|
2026-03-18 16:34:27 +08:00
|
|
|
// 默认不持久化;从 localStorage 推断:有 token 说明上次选了"记住我"
|
|
|
|
|
const _remember = ref(!!localStorage.getItem('access_token'))
|
2026-03-18 13:53:36 +08:00
|
|
|
|
2026-03-18 14:55:37 +08:00
|
|
|
// 基本 JWT 格式校验(三段式),防止垃圾值绕过路由守卫
|
|
|
|
|
const isLoggedIn = computed(() => {
|
|
|
|
|
const t = token.value
|
|
|
|
|
return !!t && t.split('.').length === 3
|
|
|
|
|
})
|
2026-03-18 13:53:36 +08:00
|
|
|
const isAdmin = computed(() => user.value?.role === 'admin')
|
|
|
|
|
const username = computed(() => user.value?.username || '')
|
|
|
|
|
|
2026-03-18 14:55:37 +08:00
|
|
|
function setToken(accessToken: string, newRefreshToken: string, remember = true) {
|
2026-03-18 13:53:36 +08:00
|
|
|
token.value = accessToken
|
|
|
|
|
refreshToken.value = newRefreshToken
|
2026-03-18 16:23:58 +08:00
|
|
|
_remember.value = remember
|
2026-03-18 14:55:37 +08:00
|
|
|
if (remember) {
|
|
|
|
|
localStorage.setItem('access_token', accessToken)
|
|
|
|
|
localStorage.setItem('refresh_token', newRefreshToken)
|
|
|
|
|
} else {
|
2026-03-18 16:34:27 +08:00
|
|
|
// 不记住:清除全部持久化数据,token 仅存于内存,关闭标签页即失效
|
2026-03-18 14:55:37 +08:00
|
|
|
localStorage.removeItem('access_token')
|
|
|
|
|
localStorage.removeItem('refresh_token')
|
2026-03-18 16:23:58 +08:00
|
|
|
localStorage.removeItem('user')
|
2026-03-18 14:55:37 +08:00
|
|
|
}
|
2026-03-18 13:53:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setUser(info: UserInfo) {
|
|
|
|
|
user.value = info
|
2026-03-18 16:23:58 +08:00
|
|
|
if (_remember.value) {
|
|
|
|
|
localStorage.setItem('user', JSON.stringify(info))
|
|
|
|
|
}
|
2026-03-18 13:53:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function fetchCurrentUser() {
|
2026-03-18 16:23:58 +08:00
|
|
|
const data = await api.get<UserInfo>('/api/v1/me')
|
2026-03-18 13:53:36 +08:00
|
|
|
setUser(data)
|
|
|
|
|
return data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function logout() {
|
|
|
|
|
token.value = null
|
|
|
|
|
refreshToken.value = null
|
|
|
|
|
user.value = null
|
2026-03-18 16:34:27 +08:00
|
|
|
_remember.value = false
|
2026-03-18 13:53:36 +08:00
|
|
|
localStorage.removeItem('access_token')
|
|
|
|
|
localStorage.removeItem('refresh_token')
|
|
|
|
|
localStorage.removeItem('user')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化:从 localStorage 恢复用户信息
|
|
|
|
|
const savedUser = localStorage.getItem('user')
|
|
|
|
|
if (savedUser) {
|
|
|
|
|
try {
|
|
|
|
|
user.value = JSON.parse(savedUser)
|
|
|
|
|
} catch {
|
|
|
|
|
user.value = null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-18 18:04:41 +08:00
|
|
|
async function updateProfile(data: { email?: string; ext?: Record<string, unknown> }) {
|
|
|
|
|
const result = await api.put<UserInfo>('/api/v1/me/profile', data)
|
|
|
|
|
setUser(result)
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function changePassword(data: {
|
|
|
|
|
old_password: string
|
|
|
|
|
new_password: string
|
|
|
|
|
new_password_confirmation: string
|
|
|
|
|
}) {
|
|
|
|
|
await api.put('/api/v1/me/password', data)
|
|
|
|
|
logout()
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-18 13:53:36 +08:00
|
|
|
return {
|
|
|
|
|
token,
|
|
|
|
|
refreshToken,
|
|
|
|
|
user,
|
|
|
|
|
isLoggedIn,
|
|
|
|
|
isAdmin,
|
|
|
|
|
username,
|
|
|
|
|
setToken,
|
|
|
|
|
setUser,
|
|
|
|
|
fetchCurrentUser,
|
|
|
|
|
logout,
|
2026-03-18 18:04:41 +08:00
|
|
|
updateProfile,
|
|
|
|
|
changePassword,
|
2026-03-18 13:53:36 +08:00
|
|
|
}
|
|
|
|
|
})
|