这是一个基于 React + TypeScript + Ant Design 开发的向明天系统前端项目。
技术栈
- React 19
- TypeScript
- Ant Design 5.x
- Redux Toolkit
- React Router
- Axios
- Less
环境要求
- Node.js (推荐使用最新LTS版本)
- npm 或 yarn
安装步骤
- 克隆项目到本地
git clone [https://gitee.com/to-tomorrow-xmt/react.git]
- 进入项目目录
cd remote-monitoring-system
- 安装依赖
npm install
# 或使用 yarn
yarn install
开发环境运行
npm start
# 或使用 yarn
yarn start
项目将在开发模式下运行,访问 http://localhost:3000 查看效果。
生产环境构建
npm run build
# 或使用 yarn
yarn build
构建后的文件将生成在 build
目录中。
项目结构
src/
├── api/ # API 接口定义
├── assets/ # 静态资源
├── components/ # 公共组件
├── pages/ # 页面组件
├── redux/ # Redux 状态管理
├── router/ # 路由配置
├── styles/ # 全局样式
├── types/ # TypeScript 类型定义
└── utils/ # 工具函数
主要功能
- 用户认证与授权
- 数据可视化
- 系统设置
- 封装接口请求数据
开发规范
- 使用 TypeScript 进行开发
- 遵循 ESLint 代码规范
- 使用 Prettier 进行代码格式化
- 组件命名采用 PascalCase
- 文件命名采用 kebab-case
接口配置文件
在 src/config
目录下创建 api.config.ts
文件:
// src/config/api.config.ts
export const API_CONFIG = {
baseURL: process.env.REACT_APP_API_URL,
timeout: 10000,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
},
};
跨域处理
开发环境跨域配置
在项目根目录下的 craco.config.js
文件中配置开发环境代理:
// craco.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: '',//真实地址
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
},
},
};
生产环境跨域处理
生产环境跨域需要在后端服务器进行配置,以下是常见的配置方式:
- Nginx 配置示例:
server {
listen 80;
server_name your-domain.com;
location /api {
proxy_pass http://backend-server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 跨域配置
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
}
- 后端服务器配置示例(以 Node.js Express 为例):
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: process.env.REACT_APP_BASE_URL,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
请求配置
项目使用 Axios 进行 HTTP 请求,主要配置如下:
// 基础配置
const baseURL = 'http://your-api-domain.com/api';
const timeout = 10000; // 请求超时时间
// 请求拦截器
axios.interceptors.request.use(
(config) => {
// 添加token
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
axios.interceptors.response.use(
(response) => {
return response.data;
},
(error) => {
// 处理错误响应
if (error.response.status === 401) {
// 处理未授权
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
请求方法示例
// GET 请求
const getData = async (params: any) => {
try {
const response = await axios.get('/endpoint', { params });
return response;
} catch (error) {
console.error('请求失败:', error);
throw error;
}
};
// POST 请求
const postData = async (data: any) => {
try {
const response = await axios.post('/endpoint', data);
return response;
} catch (error) {
console.error('请求失败:', error);
throw error;
}
};
// PUT 请求
const updateData = async (id: string, data: any) => {
try {
const response = await axios.put(`/endpoint/${id}`, data);
return response;
} catch (error) {
console.error('请求失败:', error);
throw error;
}
};
// DELETE 请求
const deleteData = async (id: string) => {
try {
const response = await axios.delete(`/endpoint/${id}`);
return response;
} catch (error) {
console.error('请求失败:', error);
throw error;
}
};
错误处理
项目使用统一的错误处理机制:
- 网络错误:显示"网络连接失败,请检查网络设置"
- 401 未授权:自动跳转到登录页面
- 403 禁止访问:显示"没有权限访问该资源"
- 404 资源不存在:显示"请求的资源不存在"
- 500 服务器错误:显示"服务器内部错误,请稍后重试"
请求封装
建议将 API 请求封装在 src/api
目录下,按模块组织:
src/api/
├── auth.ts # 认证相关接口
├── device.ts # 设备相关接口
├── monitor.ts # 监控相关接口
└── index.ts # 统一导出
权限路由说明
<!-- 路由格式 -->
使用方式,登录以后后端把这个数据放给角色,根据这个格式,把所有路径路由配置放在这里,读取的时候让后台判断,返回那些路径,与后端沟通好.
<!-- 把路由配置放在这里 -->
parentId: id;
index: index;
title:一级路由名称
icon:图标 我用的是iconfont 的图标 根据自己情况替换就行了;
type: group;
children: [ //子级路由
index:index;
title:二级路由名称
path:path;
name:name;
component:文件读取路径 读取pages 文件 路径// 看不明白的就把这里的路径和pages 下的路径对比一下就明白了
menuType:menuType;
meta: 路由原信息
] ;
"nav": [
{
"parentId": "1",
"index": "1",
"title": "首页",
"icon": "icon-shouye",
"type": "group",
"children": [
{
"index": "1-1",
"title": "首页",
"name": "home",
"path": "/home",
"component": "shouYe/index",
"menuType": 0,
"meta": {
"selectIndex": "1-1",
"check": true
}
}
]
},
{
"parentId": "2",
"index": "2",
"title": "设备管理",
"icon": "icon-shebei",
"type": "group",
"children": [
{
"index": "2-1",
"title": "设备列表",
"name": "shebei",
"path": "/shebei",
"component": "shebei/shebei",
"menuType": 0,
"meta": {
"selectIndex": "2-1",
"check": true
}
}
]
},
{
"parentId": "3",
"index": "3",
"title": "模块管理",
"icon": "icon-mokuai",
"type": "group",
"children": [
{
"index": "3-1",
"title": "模块列表",
"name": "mokuai",
"path": "/mokuai",
"component": "mokuai/Mokuai",
"menuType": 0,
"meta": {
"selectIndex": "3-1",
"check": true
}
}
]
},
{
"parentId": "4",
"index": "4",
"title": "标靶检测",
"icon": "icon-mubiaobachang1",
"type": "group",
"children": [
{
"index": "4-1",
"title": "报警列表",
"name": "jingIndex",
"path": "/jingIndex",
"component": "biaoba/index",
"menuType": 0,
"meta": {
"selectIndex": "4-1",
"check": true
}
},
{
"index": "4-2",
"title": "标靶检测",
"name": "biaoba",
"path": "/biaoba",
"component": "biaoba/biaoba",
"menuType": 0,
"meta": {
"selectIndex": "4-2",
"check": true
}
},
{
"index": "4-3",
"title": "标靶报警",
"name": "baojing",
"path": "/baojing",
"component": "biaoba/baojing",
"menuType": 0,
"meta": {
"selectIndex": "4-3",
"check": true
}
},
{
"index": "4-4",
"title": "报警等级",
"name": "dengji",
"path": "/dengji",
"component": "biaoba/dengji",
"menuType": 0,
"meta": {
"selectIndex": "4-4",
"check": true
}
}
]
}
]