生产管理系统 - 将用户基础数据同步到zustand
This commit is contained in:
@@ -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',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
Reference in New Issue
Block a user