Files
hotel-biz-h5/src/stores/auth.ts

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
}
})