生产管理系统 - 将用户基础数据同步到zustand

This commit is contained in:
2025-11-04 20:32:28 +08:00
parent e92be97393
commit c386350df5
4 changed files with 102 additions and 149 deletions

View File

@@ -8,7 +8,7 @@
'use client'; 'use client';
import { Card } from '@/components/ui/card'; import { Card } from '@/components/ui/card';
import { Building2, Users, Layers } from 'lucide-react'; import { Building2, Layers, GitBranch } from 'lucide-react';
import { DepartmentStats } from '../types'; import { DepartmentStats } from '../types';
interface DepartmentStatsCardsProps { interface DepartmentStatsCardsProps {
@@ -31,7 +31,7 @@ export function DepartmentStatsCards({
{ {
label: '二级部门', label: '二级部门',
value: stats.level2, 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', color: 'text-green-600 dark:text-green-400',
bg: 'bg-green-50 dark:bg-green-950', bg: 'bg-green-50 dark:bg-green-950',
}, },

View File

@@ -171,21 +171,33 @@ export default function DepartmentManagementPage() {
} }
}; };
// 统计部门数量 // 统计部门数量(递归计算所有层级)
const countDepartments = (depts: Department[]): { level1: number; level2: number; total: number } => { const countDepartments = (depts: Department[]): { level1: number; level2: number; total: number } => {
let level1 = 0; let level1 = 0;
let level2 = 0; let level2 = 0;
let total = 0;
depts.forEach(dept => { const countRecursive = (departments: Department[]) => {
if (!dept.parentId) { departments.forEach(dept => {
level1++; total++; // 每个部门都计入总数
if (dept.children) {
level2 += dept.children.length; // 根据level字段统计各级部门
if (dept.level === 1) {
level1++; // 统计一级部门
} else if (dept.level === 2) {
level2++; // 统计二级部门
} }
}
});
return { level1, level2, total: level1 + level2 }; // 递归计算子部门
if (dept.children && dept.children.length > 0) {
countRecursive(dept.children);
}
});
};
countRecursive(depts);
return { level1, level2, total };
}; };
const stats = countDepartments(state.departments); const stats = countDepartments(state.departments);

View File

@@ -2,6 +2,7 @@
import React, { createContext, useContext, useState, ReactNode, useRef } from 'react'; import React, { createContext, useContext, useState, ReactNode, useRef } from 'react';
import { getCurrentUserInfoApiV1AuthMeGet, refreshTokenApiV1AuthRefreshPost } from '@/lib/api/sdk.gen'; import { getCurrentUserInfoApiV1AuthMeGet, refreshTokenApiV1AuthRefreshPost } from '@/lib/api/sdk.gen';
import { setAuthUser, getAuthUser, AuthUser } from '@/stores/modules/auth';
// Cookie 操作工具 // Cookie 操作工具
const setTokenCookie = (token: string) => { const setTokenCookie = (token: string) => {
@@ -216,7 +217,11 @@ export function AuthProvider({ children }: AuthProviderProps) {
...response.data, // 合并最新的用户信息 ...response.data, // 合并最新的用户信息
}; };
setUser(updatedUserData); setUser(updatedUserData);
// 存储到 Zustand store
setAuthUser(response.data);
console.log('✅ 用户验证成功,最新用户信息:', response.data); console.log('✅ 用户验证成功,最新用户信息:', response.data);
console.log('📦 从 Zustand store 取出的用户数据:', getAuthUser());
// 验证成功后,启动 token 自动刷新定时器 // 验证成功后,启动 token 自动刷新定时器
startTokenRefresh(); startTokenRefresh();

View File

@@ -1,150 +1,86 @@
import { create } from 'zustand' import { create } from 'zustand';
import { persist } from 'zustand/middleware' import { getCurrentUserInfoApiV1AuthMeGet } from '@/lib/api/sdk.gen';
import { User, LoginRequest, PhoneLoginRequest, LoginResponse } from '@api/modules/auth'
import { authApi } from '@api'
interface AuthState { // Auth user interface definition
user: User | null export interface AuthUser {
token: string | null email: string;
refreshToken: string | null username: string;
isAuthenticated: boolean full_name: string | null;
isLoading: boolean phone: string;
error: string | null 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 { // Auth state interface
login: (credentials: LoginRequest) => Promise<void> export interface AuthState {
loginByPhone: (credentials: PhoneLoginRequest) => Promise<void> user: AuthUser | null;
logout: () => void setAuthUser: (user: AuthUser | null) => void;
refreshToken: () => Promise<void> getAuthUser: () => AuthUser | null;
getUserInfo: () => Promise<void>
updateUserInfo: (data: Partial<User>) => Promise<void>
clearError: () => void
setLoading: (loading: boolean) => void
} }
export const useAuthStore = create<AuthState & AuthActions>()( // Create auth store
persist( export const useAuthStore = create<AuthState>((set, get) => ({
(set, get) => ({ user: null,
// State
user: null,
token: null,
refreshToken: null,
isAuthenticated: false,
isLoading: false,
error: null,
// Actions setAuthUser: (user: AuthUser | null) => {
login: async (credentials) => { set({ user });
try { },
set({ isLoading: true, error: null })
const response = await authApi.login(credentials)
const { token, refreshToken, user } = response.data
localStorage.setItem('token', token) getAuthUser: () => {
localStorage.setItem('refreshToken', refreshToken) return get().user;
},
}));
set({ // Export functions for direct usage
user, export const setAuthUser = (user: AuthUser | null) => {
token, useAuthStore.getState().setAuthUser(user);
refreshToken, };
isAuthenticated: true,
isLoading: false export const getAuthUser = (): AuthUser | null => {
}) return useAuthStore.getState().getAuthUser();
} catch (error) { };
set({
error: error instanceof Error ? error.message : '登录失败', // Validate and update user info from API
isLoading: false export const validateAndUpdateUser = async (token: string): Promise<boolean> => {
}) try {
} // 使用 SDK 调用 /api/v1/auth/me 验证用户信息
const response = await getCurrentUserInfoApiV1AuthMeGet({
headers: {
'Authorization': `Bearer ${token}`,
}, },
});
loginByPhone: async (credentials) => { if (response.data) {
try { // 更新用户信息(可能包含最新的权限、角色等)
set({ isLoading: true, error: null }) const currentUser = getAuthUser();
const response = await authApi.loginByPhone(credentials) if (currentUser) {
const { token, refreshToken, user } = response.data const updatedUserData = {
...currentUser,
...response.data, // 合并最新的用户信息
};
setAuthUser(updatedUserData);
localStorage.setItem('token', token) // 打印存储后的用户数据,用于调试
localStorage.setItem('refreshToken', refreshToken) console.log('从Zustand取出的用户数据:', getAuthUser());
}
set({ return true;
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
})
} }
) return false;
) } catch (error) {
console.error('Failed to validate user info:', error);
return false;
}
};
export default useAuthStore;