122 lines
3.1 KiB
TypeScript
122 lines
3.1 KiB
TypeScript
import { computed, ref } from 'vue'
|
|
import { defineStore } from 'pinia'
|
|
import {
|
|
getBindStaffInfo,
|
|
loginByMobile,
|
|
type OrganizationMemberInfo
|
|
} from '@/api/auth'
|
|
import type { TokenResponse } from '@/types/api'
|
|
import {
|
|
AUTH_EXPIRED_EVENT,
|
|
AUTH_STORAGE_KEYS,
|
|
AUTH_TOKEN_UPDATED_EVENT,
|
|
clearAuthStorage,
|
|
persistAuthToken,
|
|
readStoredAccessToken,
|
|
readStoredRefreshToken
|
|
} from '@/utils/authStorage'
|
|
import { env } from '@/utils/env'
|
|
|
|
export interface StaffUser {
|
|
id?: string
|
|
username?: string
|
|
phone?: string
|
|
tenantId?: string | number
|
|
}
|
|
|
|
const readUser = (): StaffUser | null => {
|
|
const raw = localStorage.getItem(AUTH_STORAGE_KEYS.user)
|
|
if (!raw) return null
|
|
try {
|
|
return JSON.parse(raw) as StaffUser
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
const readMember = (): OrganizationMemberInfo | null => {
|
|
const raw = localStorage.getItem(AUTH_STORAGE_KEYS.member)
|
|
if (!raw) return null
|
|
try {
|
|
return JSON.parse(raw) as OrganizationMemberInfo
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export const useAuthStore = defineStore('auth', () => {
|
|
const token = ref(localStorage.getItem(AUTH_STORAGE_KEYS.token) || '')
|
|
const refreshToken = ref(localStorage.getItem(AUTH_STORAGE_KEYS.refreshToken) || '')
|
|
const user = ref<StaffUser | null>(readUser())
|
|
const memberInfo = ref<OrganizationMemberInfo | null>(readMember())
|
|
|
|
const isLoggedIn = computed(() => Boolean(token.value))
|
|
const hasOrganization = computed(() => Boolean(memberInfo.value?.organizationId))
|
|
|
|
const persistToken = (payload: TokenResponse, phone: string) => {
|
|
const storedToken = persistAuthToken(payload)
|
|
token.value = storedToken.accessToken
|
|
refreshToken.value = storedToken.refreshToken
|
|
user.value = {
|
|
id: payload.user_id,
|
|
username: payload.username || phone,
|
|
phone,
|
|
tenantId: payload.tenant_id
|
|
}
|
|
|
|
localStorage.setItem(AUTH_STORAGE_KEYS.user, JSON.stringify(user.value))
|
|
}
|
|
|
|
const login = async (phone: string, code: string) => {
|
|
const payload = await loginByMobile(phone, code)
|
|
persistToken(payload, phone)
|
|
try {
|
|
const member = await getBindStaffInfo()
|
|
if (!member?.organizationId || !member?.memberId) {
|
|
throw new Error('未绑定组织,请联系管理员')
|
|
}
|
|
memberInfo.value = member
|
|
localStorage.setItem(AUTH_STORAGE_KEYS.member, JSON.stringify(member))
|
|
} catch (error) {
|
|
logout()
|
|
throw new Error('未绑定组织,请联系管理员')
|
|
}
|
|
}
|
|
|
|
const resetState = () => {
|
|
token.value = ''
|
|
refreshToken.value = ''
|
|
user.value = null
|
|
memberInfo.value = null
|
|
}
|
|
|
|
const syncStoredToken = () => {
|
|
token.value = readStoredAccessToken()
|
|
refreshToken.value = readStoredRefreshToken()
|
|
}
|
|
|
|
const logout = () => {
|
|
resetState()
|
|
clearAuthStorage()
|
|
}
|
|
|
|
if (typeof window !== 'undefined') {
|
|
window.addEventListener(AUTH_EXPIRED_EVENT, resetState)
|
|
window.addEventListener(AUTH_TOKEN_UPDATED_EVENT, syncStoredToken)
|
|
}
|
|
|
|
return {
|
|
token,
|
|
refreshToken,
|
|
user,
|
|
memberInfo,
|
|
hasOrganization,
|
|
isLoggedIn,
|
|
isMockMode: env.useMock,
|
|
clientId: env.clientId,
|
|
clientConfigId: env.clientConfigId,
|
|
login,
|
|
logout
|
|
}
|
|
})
|