feat(frontend): 完成品牌 SVG 与后台 Phase 1 基础切片
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { create } from 'zustand'
|
||||
|
||||
import { changeAdminPassword, fetchAdminMe, loginAdmin, logoutAdmin } from '@/features/admin/api'
|
||||
import type { AdminUser } from '@/features/admin/types'
|
||||
|
||||
const ADMIN_ID_KEY = 'admin_id'
|
||||
const ADMIN_USERNAME_KEY = 'admin_username'
|
||||
const ADMIN_PASSWORD_MUST_CHANGE_KEY = 'admin_password_must_change'
|
||||
|
||||
function saveAdminHint(admin: AdminUser) {
|
||||
localStorage.setItem(ADMIN_ID_KEY, String(admin.id))
|
||||
localStorage.setItem(ADMIN_USERNAME_KEY, admin.username)
|
||||
localStorage.setItem(ADMIN_PASSWORD_MUST_CHANGE_KEY, String(admin.password_must_change))
|
||||
}
|
||||
|
||||
function clearAdminHint() {
|
||||
localStorage.removeItem(ADMIN_ID_KEY)
|
||||
localStorage.removeItem(ADMIN_USERNAME_KEY)
|
||||
localStorage.removeItem(ADMIN_PASSWORD_MUST_CHANGE_KEY)
|
||||
}
|
||||
|
||||
interface AdminSessionState {
|
||||
admin: AdminUser | null
|
||||
loaded: boolean
|
||||
loading: boolean
|
||||
login: (username: string, password: string, captchaId: string, captchaCode: string) => Promise<void>
|
||||
loadMe: () => Promise<void>
|
||||
logout: () => Promise<void>
|
||||
changePassword: (oldPassword: string, newPassword: string) => Promise<void>
|
||||
hasPermission: (code: string) => boolean
|
||||
isSuperAdmin: () => boolean
|
||||
}
|
||||
|
||||
export const useAdminSessionStore = create<AdminSessionState>((set, get) => ({
|
||||
admin: null,
|
||||
loaded: false,
|
||||
loading: false,
|
||||
|
||||
async login(username, password, captchaId, captchaCode) {
|
||||
set({ loading: true })
|
||||
try {
|
||||
const result = await loginAdmin(username, password, captchaId, captchaCode)
|
||||
saveAdminHint(result.admin)
|
||||
set({ admin: result.admin, loaded: true })
|
||||
} finally {
|
||||
set({ loading: false })
|
||||
}
|
||||
},
|
||||
|
||||
async loadMe() {
|
||||
if (get().loading) return
|
||||
set({ loading: true })
|
||||
try {
|
||||
const admin = await fetchAdminMe()
|
||||
saveAdminHint(admin)
|
||||
set({ admin, loaded: true })
|
||||
} catch {
|
||||
clearAdminHint()
|
||||
set({ admin: null, loaded: true })
|
||||
} finally {
|
||||
set({ loading: false })
|
||||
}
|
||||
},
|
||||
|
||||
async logout() {
|
||||
try {
|
||||
await logoutAdmin()
|
||||
} catch {
|
||||
// 即使服务端会话失效,也要清理本地提示并回到登录页。
|
||||
}
|
||||
clearAdminHint()
|
||||
set({ admin: null, loaded: true })
|
||||
},
|
||||
|
||||
async changePassword(oldPassword, newPassword) {
|
||||
await changeAdminPassword(oldPassword, newPassword)
|
||||
const admin = await fetchAdminMe()
|
||||
saveAdminHint(admin)
|
||||
set({ admin, loaded: true })
|
||||
},
|
||||
|
||||
hasPermission(code) {
|
||||
const permissions = get().admin?.permissions ?? []
|
||||
return permissions.includes('*') || permissions.includes(code)
|
||||
},
|
||||
|
||||
isSuperAdmin() {
|
||||
const admin = get().admin
|
||||
return Boolean(
|
||||
admin?.permissions.includes('*') || admin?.roles.some(role => role.code === 'super_admin')
|
||||
)
|
||||
},
|
||||
}))
|
||||
Reference in New Issue
Block a user