完善个人中心页面
This commit is contained in:
11
src/components/stores/app.ts
Normal file
11
src/components/stores/app.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { create } from "zustand"
|
||||
import { API_BASE_URL } from "@/lib/api"
|
||||
|
||||
// ==================== 应用配置 ====================
|
||||
// 后端地址等运行时配置统一从 store 读取,初始值来自 import.meta.env(见 lib/api.ts)
|
||||
|
||||
type AppState = {
|
||||
apiUrl: string
|
||||
}
|
||||
|
||||
export const useAppStore = create<AppState>()(() => ({ apiUrl: API_BASE_URL }))
|
||||
54
src/components/stores/client.ts
Normal file
54
src/components/stores/client.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { create } from "zustand"
|
||||
|
||||
|
||||
type ClientState = {
|
||||
breakpoint: {
|
||||
sm: boolean
|
||||
md: boolean
|
||||
lg: boolean
|
||||
xl: boolean
|
||||
}
|
||||
}
|
||||
|
||||
type ClientActions = {
|
||||
setBreakpoints: (breakpoints: Partial<ClientState["breakpoint"]>) => void
|
||||
}
|
||||
|
||||
export type ClientStore = ClientState & ClientActions
|
||||
|
||||
export const useClientStore = create<ClientStore>()(set => ({
|
||||
breakpoint: { sm: false, md: false, lg: false, xl: false },
|
||||
setBreakpoints: breakpoints =>
|
||||
set(state => ({
|
||||
breakpoint: { ...state.breakpoint, ...breakpoints },
|
||||
})),
|
||||
}))
|
||||
|
||||
let initialized = false
|
||||
|
||||
// 应用入口调用一次,开始监听窗口断点变化
|
||||
export function initClientStore() {
|
||||
if (initialized) return
|
||||
initialized = true
|
||||
|
||||
const queries = {
|
||||
sm: window.matchMedia("(width >= 40rem)"),
|
||||
md: window.matchMedia("(width >= 48rem)"),
|
||||
lg: window.matchMedia("(width >= 64rem)"),
|
||||
xl: window.matchMedia("(width >= 80rem)"),
|
||||
}
|
||||
const setBreakpoints = useClientStore.getState().setBreakpoints
|
||||
|
||||
setBreakpoints({
|
||||
sm: queries.sm.matches,
|
||||
md: queries.md.matches,
|
||||
lg: queries.lg.matches,
|
||||
xl: queries.xl.matches,
|
||||
})
|
||||
|
||||
for (const key of Object.keys(queries) as (keyof typeof queries)[]) {
|
||||
queries[key].addEventListener("change", e => {
|
||||
setBreakpoints({ [key]: e.matches })
|
||||
})
|
||||
}
|
||||
}
|
||||
41
src/components/stores/dashboard.ts
Normal file
41
src/components/stores/dashboard.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { create } from "zustand"
|
||||
import { fetchAgreementStatus } from "@/api/agreement"
|
||||
import { fetchApiIndex } from "@/api/dashboard"
|
||||
import type { ApiIndexItem } from "@/lib/models/dashboard"
|
||||
|
||||
// ==================== 个人中心账户总览 ====================
|
||||
// 数据源:.NET /user/ApiIndex;协议签署状态:php-api /tencent/index/get_is_upload
|
||||
|
||||
export type DashboardState = {
|
||||
data: ApiIndexItem | null
|
||||
agreementSigned: boolean | null
|
||||
loading: boolean
|
||||
error: string | null
|
||||
}
|
||||
|
||||
type DashboardActions = {
|
||||
refresh: () => Promise<void>
|
||||
refreshAgreement: () => Promise<void>
|
||||
}
|
||||
|
||||
export type DashboardStore = DashboardState & DashboardActions
|
||||
|
||||
export const useDashboardStore = create<DashboardStore>()(set => ({
|
||||
data: null,
|
||||
agreementSigned: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
refresh: async () => {
|
||||
set({ loading: true })
|
||||
const res = await fetchApiIndex()
|
||||
if (res.success) {
|
||||
set({ data: res.data, error: null, loading: false })
|
||||
} else {
|
||||
set({ error: res.message, loading: false })
|
||||
}
|
||||
},
|
||||
refreshAgreement: async () => {
|
||||
const res = await fetchAgreementStatus()
|
||||
if (res.success) set({ agreementSigned: res.data })
|
||||
},
|
||||
}))
|
||||
20
src/components/stores/layout.ts
Normal file
20
src/components/stores/layout.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { create } from "zustand"
|
||||
|
||||
|
||||
|
||||
type LayoutState = {
|
||||
navbar: boolean
|
||||
}
|
||||
|
||||
type LayoutActions = {
|
||||
setNavbar: (navbar: boolean) => void
|
||||
toggleNavbar: () => void
|
||||
}
|
||||
|
||||
export type LayoutStore = LayoutState & LayoutActions
|
||||
|
||||
export const useLayoutStore = create<LayoutStore>()(set => ({
|
||||
navbar: false,
|
||||
setNavbar: navbar => set({ navbar }),
|
||||
toggleNavbar: () => set(state => ({ navbar: !state.navbar })),
|
||||
}))
|
||||
34
src/components/stores/profile.ts
Normal file
34
src/components/stores/profile.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { create } from "zustand"
|
||||
import {
|
||||
AUTH_EVENT,
|
||||
getUserInfo,
|
||||
getUserToken,
|
||||
type UserInfoRecord,
|
||||
} from "@/api/token"
|
||||
|
||||
|
||||
export type ProfileState = {
|
||||
token: string | null
|
||||
userInfo: UserInfoRecord | null
|
||||
}
|
||||
|
||||
type ProfileActions = {
|
||||
refreshFromStorage: () => void
|
||||
}
|
||||
|
||||
export type ProfileStore = ProfileState & ProfileActions
|
||||
|
||||
export const useProfileStore = create<ProfileStore>()(set => ({
|
||||
token: getUserToken(),
|
||||
userInfo: getUserInfo<UserInfoRecord>(),
|
||||
refreshFromStorage: () => {
|
||||
set({ token: getUserToken(), userInfo: getUserInfo<UserInfoRecord>() })
|
||||
},
|
||||
}))
|
||||
|
||||
// 应用入口调用一次,监听登录态变化(含跨标签页 focus 同步)
|
||||
export function initProfileStore() {
|
||||
const sync = () => useProfileStore.getState().refreshFromStorage()
|
||||
window.addEventListener(AUTH_EVENT, sync)
|
||||
window.addEventListener("focus", sync)
|
||||
}
|
||||
Reference in New Issue
Block a user