生产管理系统 - 将用户基础数据同步到zustand
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
'use client';
|
||||
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { Building2, Users, Layers } from 'lucide-react';
|
||||
import { Building2, Layers, GitBranch } from 'lucide-react';
|
||||
import { DepartmentStats } from '../types';
|
||||
|
||||
interface DepartmentStatsCardsProps {
|
||||
@@ -31,7 +31,7 @@ export function DepartmentStatsCards({
|
||||
{
|
||||
label: '二级部门',
|
||||
value: stats.level2,
|
||||
icon: <Users className="w-5 h-5" />,
|
||||
icon: <GitBranch className="w-5 h-5" />,
|
||||
color: 'text-green-600 dark:text-green-400',
|
||||
bg: 'bg-green-50 dark:bg-green-950',
|
||||
},
|
||||
|
||||
@@ -171,21 +171,33 @@ export default function DepartmentManagementPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// 统计部门数量
|
||||
// 统计部门数量(递归计算所有层级)
|
||||
const countDepartments = (depts: Department[]): { level1: number; level2: number; total: number } => {
|
||||
let level1 = 0;
|
||||
let level2 = 0;
|
||||
let total = 0;
|
||||
|
||||
depts.forEach(dept => {
|
||||
if (!dept.parentId) {
|
||||
level1++;
|
||||
if (dept.children) {
|
||||
level2 += dept.children.length;
|
||||
const countRecursive = (departments: Department[]) => {
|
||||
departments.forEach(dept => {
|
||||
total++; // 每个部门都计入总数
|
||||
|
||||
// 根据level字段统计各级部门
|
||||
if (dept.level === 1) {
|
||||
level1++; // 统计一级部门
|
||||
} else if (dept.level === 2) {
|
||||
level2++; // 统计二级部门
|
||||
}
|
||||
|
||||
// 递归计算子部门
|
||||
if (dept.children && dept.children.length > 0) {
|
||||
countRecursive(dept.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return { level1, level2, total: level1 + level2 };
|
||||
countRecursive(depts);
|
||||
|
||||
return { level1, level2, total };
|
||||
};
|
||||
|
||||
const stats = countDepartments(state.departments);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import React, { createContext, useContext, useState, ReactNode, useRef } from 'react';
|
||||
import { getCurrentUserInfoApiV1AuthMeGet, refreshTokenApiV1AuthRefreshPost } from '@/lib/api/sdk.gen';
|
||||
import { setAuthUser, getAuthUser, AuthUser } from '@/stores/modules/auth';
|
||||
|
||||
// Cookie 操作工具
|
||||
const setTokenCookie = (token: string) => {
|
||||
@@ -216,7 +217,11 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
||||
...response.data, // 合并最新的用户信息
|
||||
};
|
||||
setUser(updatedUserData);
|
||||
|
||||
// 存储到 Zustand store
|
||||
setAuthUser(response.data);
|
||||
console.log('✅ 用户验证成功,最新用户信息:', response.data);
|
||||
console.log('📦 从 Zustand store 取出的用户数据:', getAuthUser());
|
||||
|
||||
// 验证成功后,启动 token 自动刷新定时器
|
||||
startTokenRefresh();
|
||||
|
||||
@@ -1,150 +1,86 @@
|
||||
import { create } from 'zustand'
|
||||
import { persist } from 'zustand/middleware'
|
||||
import { User, LoginRequest, PhoneLoginRequest, LoginResponse } from '@api/modules/auth'
|
||||
import { authApi } from '@api'
|
||||
import { create } from 'zustand';
|
||||
import { getCurrentUserInfoApiV1AuthMeGet } from '@/lib/api/sdk.gen';
|
||||
|
||||
interface AuthState {
|
||||
user: User | null
|
||||
token: string | null
|
||||
refreshToken: string | null
|
||||
isAuthenticated: boolean
|
||||
isLoading: boolean
|
||||
error: string | null
|
||||
// Auth user interface definition
|
||||
export interface AuthUser {
|
||||
email: string;
|
||||
username: string;
|
||||
full_name: string | null;
|
||||
phone: string;
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
is_active: boolean;
|
||||
is_superuser: boolean;
|
||||
is_verified: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
last_login_at: string;
|
||||
avatar_url: string | null;
|
||||
bio: string | null;
|
||||
display_name: string;
|
||||
department_id: string | null;
|
||||
department_name: string | null;
|
||||
}
|
||||
|
||||
interface AuthActions {
|
||||
login: (credentials: LoginRequest) => Promise<void>
|
||||
loginByPhone: (credentials: PhoneLoginRequest) => Promise<void>
|
||||
logout: () => void
|
||||
refreshToken: () => Promise<void>
|
||||
getUserInfo: () => Promise<void>
|
||||
updateUserInfo: (data: Partial<User>) => Promise<void>
|
||||
clearError: () => void
|
||||
setLoading: (loading: boolean) => void
|
||||
// Auth state interface
|
||||
export interface AuthState {
|
||||
user: AuthUser | null;
|
||||
setAuthUser: (user: AuthUser | null) => void;
|
||||
getAuthUser: () => AuthUser | null;
|
||||
}
|
||||
|
||||
export const useAuthStore = create<AuthState & AuthActions>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
// State
|
||||
// Create auth store
|
||||
export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
user: null,
|
||||
token: null,
|
||||
refreshToken: null,
|
||||
isAuthenticated: false,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
|
||||
// Actions
|
||||
login: async (credentials) => {
|
||||
setAuthUser: (user: AuthUser | null) => {
|
||||
set({ user });
|
||||
},
|
||||
|
||||
getAuthUser: () => {
|
||||
return get().user;
|
||||
},
|
||||
}));
|
||||
|
||||
// Export functions for direct usage
|
||||
export const setAuthUser = (user: AuthUser | null) => {
|
||||
useAuthStore.getState().setAuthUser(user);
|
||||
};
|
||||
|
||||
export const getAuthUser = (): AuthUser | null => {
|
||||
return useAuthStore.getState().getAuthUser();
|
||||
};
|
||||
|
||||
// Validate and update user info from API
|
||||
export const validateAndUpdateUser = async (token: string): Promise<boolean> => {
|
||||
try {
|
||||
set({ isLoading: true, error: null })
|
||||
const response = await authApi.login(credentials)
|
||||
const { token, refreshToken, user } = response.data
|
||||
// 使用 SDK 调用 /api/v1/auth/me 验证用户信息
|
||||
const response = await getCurrentUserInfoApiV1AuthMeGet({
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
localStorage.setItem('token', token)
|
||||
localStorage.setItem('refreshToken', refreshToken)
|
||||
if (response.data) {
|
||||
// 更新用户信息(可能包含最新的权限、角色等)
|
||||
const currentUser = getAuthUser();
|
||||
if (currentUser) {
|
||||
const updatedUserData = {
|
||||
...currentUser,
|
||||
...response.data, // 合并最新的用户信息
|
||||
};
|
||||
setAuthUser(updatedUserData);
|
||||
|
||||
set({
|
||||
user,
|
||||
token,
|
||||
refreshToken,
|
||||
isAuthenticated: true,
|
||||
isLoading: false
|
||||
})
|
||||
// 打印存储后的用户数据,用于调试
|
||||
console.log('从Zustand取出的用户数据:', getAuthUser());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
set({
|
||||
error: error instanceof Error ? error.message : '登录失败',
|
||||
isLoading: false
|
||||
})
|
||||
console.error('Failed to validate user info:', error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
loginByPhone: async (credentials) => {
|
||||
try {
|
||||
set({ isLoading: true, error: null })
|
||||
const response = await authApi.loginByPhone(credentials)
|
||||
const { token, refreshToken, user } = response.data
|
||||
|
||||
localStorage.setItem('token', token)
|
||||
localStorage.setItem('refreshToken', refreshToken)
|
||||
|
||||
set({
|
||||
user,
|
||||
token,
|
||||
refreshToken,
|
||||
isAuthenticated: true,
|
||||
isLoading: false
|
||||
})
|
||||
} catch (error) {
|
||||
set({
|
||||
error: error instanceof Error ? error.message : '登录失败',
|
||||
isLoading: false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
logout: () => {
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('refreshToken')
|
||||
set({
|
||||
user: null,
|
||||
token: null,
|
||||
refreshToken: null,
|
||||
isAuthenticated: false,
|
||||
error: null
|
||||
})
|
||||
},
|
||||
|
||||
refreshToken: async () => {
|
||||
try {
|
||||
const { refreshToken } = get()
|
||||
if (!refreshToken) {
|
||||
get().logout()
|
||||
return
|
||||
}
|
||||
|
||||
const response = await authApi.refreshToken(refreshToken)
|
||||
const { token } = response.data
|
||||
|
||||
localStorage.setItem('token', token)
|
||||
set({ token })
|
||||
} catch (error) {
|
||||
get().logout()
|
||||
}
|
||||
},
|
||||
|
||||
getUserInfo: async () => {
|
||||
try {
|
||||
const response = await authApi.getUserInfo()
|
||||
set({ user: response.data })
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error)
|
||||
}
|
||||
},
|
||||
|
||||
updateUserInfo: async (data) => {
|
||||
try {
|
||||
const response = await authApi.updateUserInfo(data)
|
||||
set({ user: response.data })
|
||||
} catch (error) {
|
||||
set({
|
||||
error: error instanceof Error ? error.message : '更新用户信息失败'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
clearError: () => set({ error: null }),
|
||||
|
||||
setLoading: (loading) => set({ isLoading: loading })
|
||||
}),
|
||||
{
|
||||
name: 'auth-storage',
|
||||
partialize: (state) => ({
|
||||
user: state.user,
|
||||
token: state.token,
|
||||
refreshToken: state.refreshToken,
|
||||
isAuthenticated: state.isAuthenticated
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
export default useAuthStore;
|
||||
Reference in New Issue
Block a user