refactor(frontend): 重构状态管理使用Zustand替代Context API
feat(auth): 添加账户锁定功能及自动解锁机制 feat(user): 在用户模型中添加lockedUntil字段 feat(api): 实现账户锁定逻辑和剩余尝试次数提示 perf(3d): 优化3D场景状态管理性能 perf(floorplan): 优化平面图状态管理性能 chore(deps): 添加zustand依赖 chore(config): 更新安全配置锁定时间为3分钟 docs: 更新部分组件注释 style: 调整登录页面样式
This commit is contained in:
@@ -1,12 +1,39 @@
|
||||
import { useContext } from 'react';
|
||||
import FloorPlanContext from '../../context/FloorPlanContext';
|
||||
import { useFloorPlanStore } from '../../stores/floorPlanStore';
|
||||
|
||||
const useFloorPlanContext = () => {
|
||||
const context = useContext(FloorPlanContext);
|
||||
if (!context) {
|
||||
throw new Error('useFloorPlanContext 必须在 FloorPlanProvider 内使用');
|
||||
}
|
||||
return context;
|
||||
const selectedRoomId = useFloorPlanStore((s) => s.selectedRoomId);
|
||||
const selectedRack = useFloorPlanStore((s) => s.selectedRack);
|
||||
const hoveredRack = useFloorPlanStore((s) => s.hoveredRack);
|
||||
const zoom = useFloorPlanStore((s) => s.zoom);
|
||||
const offsetX = useFloorPlanStore((s) => s.offsetX);
|
||||
const offsetY = useFloorPlanStore((s) => s.offsetY);
|
||||
const detailRack = useFloorPlanStore((s) => s.detailRack);
|
||||
const detailVisible = useFloorPlanStore((s) => s.detailVisible);
|
||||
const setSelectedRoom = useFloorPlanStore((s) => s.setSelectedRoom);
|
||||
const setSelectedRack = useFloorPlanStore((s) => s.setSelectedRack);
|
||||
const setHoveredRack = useFloorPlanStore((s) => s.setHoveredRack);
|
||||
const setViewChange = useFloorPlanStore((s) => s.setViewChange);
|
||||
const showDetail = useFloorPlanStore((s) => s.showDetail);
|
||||
const hideDetail = useFloorPlanStore((s) => s.hideDetail);
|
||||
const reset = useFloorPlanStore((s) => s.reset);
|
||||
|
||||
return {
|
||||
selectedRoomId,
|
||||
selectedRack,
|
||||
hoveredRack,
|
||||
zoom,
|
||||
offsetX,
|
||||
offsetY,
|
||||
detailRack,
|
||||
detailVisible,
|
||||
setSelectedRoom,
|
||||
setSelectedRack,
|
||||
setHoveredRack,
|
||||
setViewChange,
|
||||
showDetail,
|
||||
hideDetail,
|
||||
reset,
|
||||
};
|
||||
};
|
||||
|
||||
export default useFloorPlanContext;
|
||||
export default useFloorPlanContext;
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 认证状态 Hook
|
||||
* 直接使用 Zustand Store 管理认证状态
|
||||
*/
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useAuthStore } from '../stores/authStore';
|
||||
|
||||
export const useAuth = () => {
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const token = useAuthStore((s) => s.token);
|
||||
const loading = useAuthStore((s) => s.loading);
|
||||
const initialized = useAuthStore((s) => s.initialized);
|
||||
const login = useAuthStore((s) => s.login);
|
||||
const register = useAuthStore((s) => s.register);
|
||||
const logout = useAuthStore((s) => s.logout);
|
||||
const updateUser = useAuthStore((s) => s.updateUser);
|
||||
const hasPermission = useAuthStore((s) => s.hasPermission);
|
||||
const checkAdmin = useAuthStore((s) => s.checkAdmin);
|
||||
const initialize = useAuthStore((s) => s.initialize);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
}, [initialized, initialize]);
|
||||
|
||||
return {
|
||||
user,
|
||||
token,
|
||||
loading,
|
||||
initialized,
|
||||
login,
|
||||
register,
|
||||
logout,
|
||||
updateUser,
|
||||
hasPermission,
|
||||
checkAdmin,
|
||||
};
|
||||
};
|
||||
|
||||
export default useAuth;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 系统配置 Hook
|
||||
* 直接使用 Zustand Store 管理系统配置
|
||||
*/
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useConfigStore } from '../stores/configStore';
|
||||
|
||||
export const useConfig = () => {
|
||||
const config = useConfigStore((s) => s.config);
|
||||
const loading = useConfigStore((s) => s.loading);
|
||||
const updateConfig = useConfigStore((s) => s.updateConfig);
|
||||
const reloadConfig = useConfigStore((s) => s.reloadConfig);
|
||||
const loadConfig = useConfigStore((s) => s.loadConfig);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
loadConfig();
|
||||
}
|
||||
}, [loading, loadConfig]);
|
||||
|
||||
return { config, loading, updateConfig, reloadConfig };
|
||||
};
|
||||
|
||||
export default useConfig;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useConfig } from '../context/ConfigContext';
|
||||
import { useConfigStore } from '../stores/configStore';
|
||||
|
||||
/**
|
||||
* 使用设计令牌 Hook
|
||||
@@ -7,12 +7,10 @@ import { useConfig } from '../context/ConfigContext';
|
||||
* @returns {Object} 设计令牌对象
|
||||
*/
|
||||
export const useDesignTokens = () => {
|
||||
const { config } = useConfig();
|
||||
const primaryColor = useConfigStore((s) => s.config.primary_color) || '#667eea';
|
||||
const secondaryColor = useConfigStore((s) => s.config.secondary_color) || '#764ba2';
|
||||
|
||||
const designTokens = useMemo(() => {
|
||||
const primaryColor = config?.primary_color || '#667eea';
|
||||
const secondaryColor = config?.secondary_color || '#764ba2';
|
||||
|
||||
return {
|
||||
colors: {
|
||||
primary: {
|
||||
@@ -61,7 +59,7 @@ export const useDesignTokens = () => {
|
||||
lg: '24px',
|
||||
},
|
||||
};
|
||||
}, [config?.primary_color, config?.secondary_color]);
|
||||
}, [primaryColor, secondaryColor]);
|
||||
|
||||
return designTokens;
|
||||
};
|
||||
@@ -72,10 +70,8 @@ export const useDesignTokens = () => {
|
||||
* @returns {string} RGB字符串 (如: "102, 126, 234")
|
||||
*/
|
||||
function hexToRgb(hex) {
|
||||
// 移除 # 号
|
||||
const cleanHex = hex.replace('#', '');
|
||||
|
||||
// 处理简写格式 (如: #fff)
|
||||
const fullHex =
|
||||
cleanHex.length === 3
|
||||
? cleanHex
|
||||
@@ -91,4 +87,4 @@ function hexToRgb(hex) {
|
||||
return `${r}, ${g}, ${b}`;
|
||||
}
|
||||
|
||||
export default useDesignTokens;
|
||||
export default useDesignTokens;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 平面图 Hook
|
||||
* 直接使用 Zustand Store 管理平面图状态
|
||||
*/
|
||||
|
||||
import { useFloorPlanStore } from '../stores/floorPlanStore';
|
||||
|
||||
export const useFloorPlan = () => {
|
||||
return useFloorPlanStore();
|
||||
};
|
||||
|
||||
export default useFloorPlan;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 3D场景 Hook
|
||||
* 直接使用 Zustand Store 管理3D场景状态
|
||||
*/
|
||||
|
||||
import { useScene3DStore } from '../stores/scene3DStore';
|
||||
|
||||
export const useScene3D = () => {
|
||||
return useScene3DStore();
|
||||
};
|
||||
|
||||
export default useScene3D;
|
||||
Reference in New Issue
Block a user