19 KiB
19 KiB
海洋项目管理系统 - 前端技术架构文档
1. 前端技术栈
1.1 核心框架
- React 18: 用于构建用户界面的JavaScript库
- React Router 6: 客户端路由管理
- Vite: 现代化的前端构建工具(替代Create React App)
1.2 UI组件库
- Ant Design 5: 企业级UI组件库
- @ant-design/icons: Ant Design图标库
1.3 HTTP客户端
- Axios: HTTP请求库
1.4 状态管理
- React Context API: 轻量级状态管理
- useReducer Hook: 复杂状态逻辑
1.5 表单处理
- Ant Design Form: 表单组件和验证
- react-hook-form: 表单状态管理(可选)
1.6 工具库
- dayjs: 日期处理(轻量级替代moment.js)
- lodash: 工具函数库
- classnames: 条件类名处理
1.7 开发工具
- ESLint: 代码质量检查
- Prettier: 代码格式化
- Vitest: 单元测试框架
- React Testing Library: 组件测试
- TypeScript: 类型检查(可选,当前使用JavaScript)
1.8 构建和部署
- Vite: 开发服务器和构建工具
- Docker: 容器化部署(生产环境)
2. 前端目录结构
frontend/
├── src/ # 源代码目录
│ ├── assets/ # 静态资源
│ │ ├── images/ # 图片
│ │ ├── fonts/ # 字体文件
│ │ └── styles/ # 全局样式
│ │ ├── global.css # 全局CSS
│ │ ├── variables.css # CSS变量
│ │ └── mixins.css # CSS mixins
│ ├── components/ # 可复用组件
│ │ ├── Layout/ # 布局组件
│ │ │ ├── Layout.jsx # 主布局
│ │ │ ├── Header.jsx # 顶部导航
│ │ │ └── Sidebar.jsx # 侧边栏
│ │ ├── Common/ # 通用组件
│ │ │ ├── Button.jsx # 按钮组件
│ │ │ ├── Input.jsx # 输入框组件
│ │ │ ├── Select.jsx # 选择框组件
│ │ │ ├── Table.jsx # 表格组件
│ │ │ ├── Modal.jsx # 弹窗组件
│ │ │ ├── Form.jsx # 表单组件
│ │ │ ├── Card.jsx # 卡片组件
│ │ │ └── Tag.jsx # 标签组件
│ │ ├── Business/ # 业务组件
│ │ │ ├── ProjectCard.jsx # 项目卡片
│ │ │ ├── StatCard.jsx # 统计卡片
│ │ │ └── UserAvatar.jsx # 用户头像
│ │ └── index.js # 组件导出
│ ├── pages/ # 页面组件
│ │ ├── Login/ # 登录页
│ │ │ └── Login.jsx
│ │ ├── Dashboard/ # 仪表盘
│ │ │ └── Dashboard.jsx
│ │ ├── Projects/ # 项目管理
│ │ │ ├── ProjectList.jsx # 项目列表
│ │ │ ├── ProjectForm.jsx # 项目表单
│ │ │ ├── ProjectDetail.jsx # 项目详情
│ │ │ └── ProjectStatistics.jsx # 项目统计
│ │ ├── Users/ # 用户管理(仅管理员)
│ │ │ ├── UserList.jsx # 用户列表
│ │ │ ├── UserForm.jsx # 用户表单
│ │ │ └── UserResetPassword.jsx # 重置密码
│ │ └── Statistics/ # 统计分析
│ │ └── Statistics.jsx
│ ├── contexts/ # Context上下文
│ │ ├── AuthContext.jsx # 认证上下文
│ │ └── ThemeContext.jsx # 主题上下文(可选)
│ ├── hooks/ # 自定义Hooks
│ │ ├── useAuth.js # 认证Hook
│ │ ├── useApi.js # API调用Hook
│ │ ├── usePermission.js # 权限检查Hook
│ │ ├── useTable.js # 表格Hook
│ │ ├── useForm.js # 表单Hook
│ │ └── useDebounce.js # 防抖Hook
│ ├── services/ # API服务
│ │ ├── api.js # Axios配置
│ │ ├── auth.js # 认证API
│ │ ├── user.js # 用户API
│ │ ├── project.js # 项目API
│ │ └── statistics.js # 统计API
│ ├── utils/ # 工具函数
│ │ ├── request.js # 请求封装
│ │ ├── storage.js # 本地存储
│ │ ├── auth.js # 认证工具
│ │ ├── format.js # 格式化函数
│ │ ├── validation.js # 验证函数
│ │ └── constants.js # 常量定义
│ ├── config/ # 配置文件
│ │ ├── routes.js # 路由配置
│ │ ├── menu.js # 菜单配置
│ │ ├── colors.js # 颜色配置
│ │ └── app.config.js # 应用配置
│ ├── router/ # 路由相关
│ │ ├── index.jsx # 路由配置
│ │ ├── PrivateRoute.jsx # 路由守卫
│ │ └── routes.js # 路由定义
│ ├── styles/ # 样式文件
│ │ └── index.css # 主样式文件
│ ├── App.jsx # 根组件
│ └── main.jsx # 应用入口
├── tests/ # 测试目录
│ ├── components/ # 组件测试
│ ├── pages/ # 页面测试
│ ├── hooks/ # Hooks测试
│ └── utils/ # 工具测试
├── public/ # 公共资源
│ ├── favicon.ico # 网站图标
│ ├── logo.png # Logo
│ └── robots.txt # 爬虫配置
├── docs/ # 前端文档
│ ├── frontend-architecture.md # 前端技术架构(本文档)
│ ├── component-design.md # 组件设计文档
│ ├── api-service.md # API服务封装
│ ├── state-management.md # 状态管理设计
│ ├── routing-design.md # 路由设计文档
│ └── development-guide.md # 开发指南
├── .env # 环境变量
├── .env.development # 开发环境变量
├── .env.production # 生产环境变量
├── .eslintrc.js # ESLint配置
├── .prettierrc # Prettier配置
├── package.json # 项目依赖
├── vite.config.js # Vite配置
├── index.html # HTML模板
├── WORKSTANDARDS.md # 前端工作规范
└── README.md # 前端说明文档
3. 组件架构
3.1 组件层级
App
├── AuthProvider (认证上下文)
├── Router (路由)
│ ├── PrivateRoute (路由守卫)
│ ├── Login (登录页)
│ └── Layout (主布局)
│ ├── Header (顶部导航)
│ ├── Sidebar (侧边栏)
│ └── Content (内容区)
│ ├── Dashboard (仪表盘)
│ ├── ProjectList (项目列表)
│ ├── ProjectForm (项目表单)
│ ├── ProjectDetail (项目详情)
│ ├── UserList (用户列表)
│ ├── UserForm (用户表单)
│ └── Statistics (统计页)
3.2 组件设计原则
3.2.1 单一职责原则
- 每个组件只负责一个功能
- 避免组件过大,合理拆分
3.2.2 组件复用性
- 提取可复用的通用组件到
components/Common/ - 提取业务相关组件到
components/Business/
3.2.3 组件分类
- 布局组件: Layout, Header, Sidebar
- 通用组件: Button, Input, Form, Modal, Table
- 业务组件: ProjectCard, StatCard, UserAvatar
- 页面组件: Login, Dashboard, ProjectList等
3.2.4 组件Props规范
// 推荐的Props定义方式
const MyComponent = ({
title, // 必填props
value, // 可选props
onChange, // 事件回调
className, // 样式类名
style, // 内联样式
children, // 子元素
}) => {
return <div>{title}</div>;
};
MyComponent.propTypes = {
title: PropTypes.string.isRequired,
value: PropTypes.string,
onChange: PropTypes.func,
className: PropTypes.string,
style: PropTypes.object,
children: PropTypes.node,
};
MyComponent.defaultProps = {
value: '',
onChange: () => {},
className: '',
style: {},
};
4. 状态管理
4.1 Context API方案
4.1.1 AuthContext(认证上下文)
// contexts/AuthContext.jsx
const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [token, setToken] = useState(null);
const [loading, setLoading] = useState(true);
// 登录
const login = async (username, password) => {
// 登录逻辑
};
// 登出
const logout = () => {
// 登出逻辑
};
// 检查登录状态
const checkAuth = async () => {
// 检查逻辑
};
return (
<AuthContext.Provider
value={{
user,
token,
loading,
login,
logout,
checkAuth,
isAuthenticated: !!user,
}}
>
{children}
</AuthContext.Provider>
);
};
4.1.2 ThemeContext(主题上下文,可选)
// contexts/ThemeContext.jsx
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
4.2 本地状态管理
- 使用
useState管理组件内部状态 - 使用
useReducer管理复杂的状态逻辑
4.3 表单状态管理
- 使用 Ant Design Form 组件
- 使用
react-hook-form(可选)
5. 路由设计
5.1 路由配置
// router/routes.js
const routes = [
{
path: '/login',
element: <Login />,
meta: { title: '登录', requiresAuth: false },
},
{
path: '/',
element: <Layout />,
meta: { title: '主页', requiresAuth: true },
children: [
{
path: '/dashboard',
element: <Dashboard />,
meta: { title: '仪表盘', icon: 'DashboardOutlined' },
},
{
path: '/projects',
element: <ProjectList />,
meta: { title: '项目管理', icon: 'FileTextOutlined' },
},
{
path: '/projects/create',
element: <ProjectForm />,
meta: { title: '创建项目' },
},
{
path: '/projects/:id',
element: <ProjectDetail />,
meta: { title: '项目详情' },
},
{
path: '/projects/:id/edit',
element: <ProjectForm />,
meta: { title: '编辑项目' },
},
{
path: '/users',
element: <UserList />,
meta: { title: '用户管理', icon: 'UserOutlined', requiresRole: ['admin'] },
},
{
path: '/users/create',
element: <UserForm />,
meta: { title: '创建用户', requiresRole: ['admin'] },
},
{
path: '/statistics',
element: <Statistics />,
meta: { title: '统计分析', icon: 'BarChartOutlined' },
},
],
},
];
5.2 路由守卫
// router/PrivateRoute.jsx
const PrivateRoute = ({ children, requiresAuth, requiresRole }) => {
const { isAuthenticated, user } = useAuth();
const navigate = useNavigate();
if (requiresAuth && !isAuthenticated) {
return <Navigate to="/login" replace />;
}
if (requiresRole && !requiresRole.includes(user?.role)) {
return <Navigate to="/403" replace />;
}
return children;
};
6. API服务封装
6.1 Axios配置
// services/api.js
import axios from 'axios';
import { message } from 'antd';
const api = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:5000/api/v1',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
api.interceptors.response.use(
(response) => {
return response.data;
},
(error) => {
if (error.response) {
const { status, data } = error.response;
switch (status) {
case 401:
message.error('登录已过期,请重新登录');
localStorage.removeItem('token');
window.location.href = '/login';
break;
case 403:
message.error('权限不足');
break;
case 404:
message.error('请求的资源不存在');
break;
case 500:
message.error('服务器错误');
break;
default:
message.error(data.message || '请求失败');
}
} else {
message.error('网络错误,请检查网络连接');
}
return Promise.reject(error);
}
);
export default api;
6.2 API模块化
// services/project.js
import api from './api';
export const projectAPI = {
// 获取项目列表
getList: (params) => api.get('/projects', { params }),
// 获取项目详情
getDetail: (id) => api.get(`/projects/${id}`),
// 创建项目
create: (data) => api.post('/projects', data),
// 更新项目
update: (id, data) => api.put(`/projects/${id}`, data),
// 删除项目
delete: (id) => api.delete(`/projects/${id}`),
// 获取统计信息
getStatistics: (params) => api.get('/projects/statistics', { params }),
// 获取分组统计
getGroupStatistics: (params) => api.get('/projects/statistics/group', { params }),
// 获取时间维度统计
getTimelineStatistics: (params) => api.get('/projects/statistics/timeline', { params }),
};
7. 权限控制
7.1 路由级权限
- 使用
PrivateRoute组件检查认证状态 - 使用
requiresRole属性检查角色权限
7.2 组件级权限
// hooks/usePermission.js
export const usePermission = () => {
const { user } = useAuth();
const hasRole = (roles) => {
if (!user) return false;
return roles.includes(user.role);
};
const canEdit = (resource, createdBy) => {
if (!user) return false;
if (user.role === 'admin') return true;
if (user.role === 'market' && createdBy === user.id) return true;
return false;
};
return { hasRole, canEdit };
};
7.3 按钮级权限
// 组件中使用
const { hasRole } = usePermission();
{hasRole(['admin', 'market']) && (
<Button type="primary">创建项目</Button>
)}
8. 性能优化
8.1 代码分割
import { lazy, Suspense } from 'react';
const ProjectList = lazy(() => import('./pages/Projects/ProjectList'));
const ProjectDetail = lazy(() => import('./pages/Projects/ProjectDetail'));
<Suspense fallback={<Spin />}>
<ProjectList />
</Suspense>
8.2 图片优化
- 使用懒加载
- 压缩图片文件
- 使用WebP格式
8.3 请求优化
- 防抖处理搜索请求
- 取消重复请求
- 使用缓存策略
8.4 渲染优化
- 使用
React.memo避免不必要的重渲染 - 使用
useMemo缓存计算结果 - 使用
useCallback缓存函数引用
9. 前端安全
9.1 XSS防护
- React自动转义HTML
- 避免使用
dangerouslySetInnerHTML - 输入验证和过滤
9.2 CSRF防护
- 使用Cookie SameSite属性
- 添加CSRF Token(可选)
9.3 敏感信息保护
- Token存储在LocalStorage(可改为HttpOnly Cookie)
- 不在URL中传递敏感信息
- 使用HTTPS(生产环境)
9.4 内容安全策略(CSP)
- 设置CSP头部
- 限制外部资源加载
10. 开发规范
10.1 代码风格
- 使用ESLint进行代码检查
- 使用Prettier进行代码格式化
- 遵循Airbnb JavaScript风格指南
10.2 命名规范
- 组件名使用PascalCase(如
ProjectList) - 函数和变量使用camelCase(如
getUserById) - 常量使用UPPER_SNAKE_CASE(如
API_BASE_URL) - CSS类名使用kebab-case(如
project-card)
10.3 注释规范
/**
* 获取项目列表
* @param {Object} params - 查询参数
* @param {number} params.page - 页码
* @param {number} params.pageSize - 每页数量
* @returns {Promise} 项目列表数据
*/
const getProjectList = async (params) => {
// 实现代码
};
10.4 Git提交规范
[frontend] feat: 添加项目列表页面
[frontend] fix: 修复登录bug
[frontend] style: 优化代码格式
[frontend] refactor: 重构API服务
[frontend] test: 添加组件测试
[frontend] docs: 更新文档
[frontend] chore: 更新依赖
11. 测试策略
11.1 单元测试
- 测试工具函数和自定义Hooks
- 使用Vitest测试框架
11.2 组件测试
- 测试组件渲染和交互
- 使用React Testing Library
11.3 集成测试
- 测试页面和路由
- 测试API调用
11.4 E2E测试(可选)
- 测试完整用户流程
- 使用Playwright
12. 部署方案
12.1 开发环境
npm run dev
# 访问 http://localhost:3000
12.2 生产构建
npm run build
# 生成 dist 目录
12.3 Docker部署
# Dockerfile
FROM node:18-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
12.4 Nginx配置
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
13. 相关文档
文档维护: 前端程序员 文档类型: 前端技术架构文档 最后更新: 2026-01-25