feat(frontend): 完成品牌 SVG 与后台 Phase 1 基础切片

This commit is contained in:
yml2213
2026-10-30 12:20:01 +08:00
parent 8d9481c251
commit 97167fa482
25 changed files with 2028 additions and 40 deletions
+93
View File
@@ -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')
)
},
}))